[C++ Primer Plus] 类基础知识

来源:互联网 发布:汤晓燕网络书法展 编辑:程序博客网 时间:2024/06/10 14:52
(一)  散知识

1,一种常见但不通用的规定------将类名首字母大写;将类的数据成员名中使用 m_ 前缀(m_a)或者在成员名中使用后缀 _ (a_);

2,不必在类声明中使用关键字private,因为这是类对象的默认访问控制;如:

class A{       int m_count;     //private by default        char m_name[20]; //private by default    public:        void getnumber(void);        ...};

3,将const关键字放在函数括号后面来说明这是一个“只读函数”。也就是说这个函数不会修改任何数据成员。声明和定义都应该放const关键字,以这种方式声明和定义的类函数被称为const成员函数。任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将指出错误,这无疑提高程序健壮性。

class temp{public:      temp(int age);int getAge() const;void setNum(int num);private:int age;};temp::temp(int age){this->age = age;}int temp::getAge() const{age+=10; // #Error...error C2166: l-value specifies const object #      return age;}void main(){temp a(22);cout << "age= " << a.getAge() << endl;} class A{       int m_count;     //private by default        char m_name[20]; //private by default    public:        void getnumber(void);        ...};

因为声明了const函数,所以不可以修改任何数据成员,但是在这里给age数据成员加了10 所以产生错误。

(二) 类和结构的区别

        类与结构的唯一区别,结构默认访问时public,而类为private;

(三) 内联方法

       定义于类声明中的函数都将自动成为内联函数,一般将短小的成员函数作为内联函数。

 class Test     {      public:     int CompareInt (int a, int b)      {         return a > b ? a:b;     }       private:        int m_a;     int m_b;};

        如果愿意也可以在类声明之外定义成员函数,并使其成为内联函数。为此,只需在类实现部分中定义函数时使用inline限定符即可。内联函数的特殊规则要求在每个使用它们的文件中都要对其定义,最简便的方法是将内联函数放在类的头文件中:

class Test   {     public:      int CompareInt (int a, int b); private:          int m_a;     int m_b;};    inline int Test::CompareInt (int a, int b)   //use inline in definition{     return a > b ? a:b;}

(四) 构造函数

       1, 声明和定义构造函数

       程序在声明对象时,将自动调用构造函数。构造函数的原型和函数头有一个有趣的特征---虽然没有返回值,但没有被声明为void类型,实际上构造函数没有声明类型。

        class Test::Test ( int a = 0; int b = 0)             {             m_a = a;             m_b = b;        }  


          2, 使用构造函数

       C++提供两种使用构造函数来初始化对象的方式。第一种:显式地调用构造函数:

    Test TestOne = Test(5 , 6); 

       第二种是隐式地调用构造函数:

      Test TestTwo(5 , 6); 

       需要注意的是,无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在的。因此构造函数被用来创建对象,而不是通过对象来调用。

          3, 默认构造函数

           如果没有提供任何构造函数,那么C++将自动提供默认构造函数。如上面Test类的默认构造函数可能是:    

              Test :: Test() { }; 

           但需要注意的是,当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。如果为类定义的构造函数,就必须为它提供默认构造函数,否则下面的声明将出错:

          Test TestThree; 

          因此如果要创建对象,并且不想显式地初始化,则必须提供一个不接受任何参数的默认构造函数。定义默认构造函数的方式有两种。第一种是给已有的构造函数的所有参数提供默认值,也就是说默认构造函数可以没有任何参数,如果有,则必须给所有参数都提供默认值:

         Test ( int a = 0; int b = 0);  //声明         Test::Test ( int a = 0; int b = 0)  //定义         {               m_a = a;               m_b = b;         }

           另一种方式是通过函数重载来定义另一构造函数---一个没有任何参数的构造函数:

          Test ();

        通常应提供对所有类成员做隐式初始化的默认构造函数,则上面的构造函数定义可以为:

         Test::Test ();         {              m_a = 0;              m_b = 0;         }

       一个类中可以有多个构造函数,多个构造函数的的参数一定要不一样,但只能有一个默认构造函数,所以不要同时采用以上两种方式。使用上面任何一种形式创建默认构造函数后,边可以声明对象变量,而不对他们进行显示初始化:         TestTestFour;  //隐式地调用默认构造函数  (注意区分TestTestFour(); 该声明为声明一个返回Test类对象的TestFour函数,隐式地调用默认构造函数不需要使用圆括号)

         TestTestFive = Test();   //显示地调用默认构造函数  
4, 程序中可以多次调用构造函数

      假如Test类存在如下构造函数与析构函数:

         Test ();  //默认构造函数声明         Test::Test ();   //默认构造函数定义         {              m_a = 0;              m_b = 0;         }                Test ( int a ; int b); //自定义构造函数声明         Test::Test ( int a; int b)  //自定义构造函数定义         {               m_a = a;               m_b = b;         }         ~Test(); //析构函数声明                 Test::~Test() {};    //析构函数定义 

程序中存在如下语句:

        Test TestSix( 1 ; 2);         Test TestSeven = Test( 3 ; 4);         TestSix=Test( 5 ; 6); 

        第一条语句创建一个类对象TestSix并初始化为指定值,第二条语句使用另一种语法创建并初始化TestSeven类对象,C++允许两种方式执行第二中语法,一种是其行为与第一种完全相同,另一种是允许调用构造函数来创建一个临时对象,然后将该临时对象复制到TestSeven中,并丢弃它。如果编译器使用这种方式,则将为临时对象调用析构函数。第三条语句不是对TestSix对象构造以及初始化,而是将新值赋给它。这是通过让构造函数程序创建一个新的、临时的对象,然后将其内容复制给TestSix来实现的,随后程序调用析构函数以删除临时对象。注意,第二条语句可能会创建临时对象(也可能不会),而第三条一定会创建一个临时对象。

     5, C++11列表初始化

        可以将初始语法用于类,只需提供与某个构造函数的参数列表匹配的内容,并用大括号将他们扩起:

        Test TestEight = {1; 2};  //自定义构造函数匹配        Test TestEight {}; //与默认构造函数匹配
(五) 析构函数

       和构造函数一样,析构函数也没有返回值和声明类型,与构造函数不同的是析构函数没有参数,因此Test的析构函数的原型必须为这样:

         ~Test();         

       如果Test的构造函数使用new来分配内存,则析构函数将使用delete来释放这些内存。如果Test的构造函数没有使用new来分配内存,则析构函数不承担任何重要的工作,因此可以将它定义为不执行任何操作的函数:

         Test::~Test() {}; 
(六) 作用域为类的常量
        有时候将符号常量的作用域为类很有用。例如将类声明可能使用的字面值30来指定数组长度。如:
        class Bakery        {        private:        const int Month = 12;        double costs[Month];        ...
这是行不通的,因为声明类只是描述了对象的形式,并没有创建对象。因此在创建对象前将没有用于存储值的
空间。然而,有两种方式可以实现这个目标,并且效果相同:

        第一:在类中声明一个枚举。在类声明中声明的枚举作用域为整个类,因此可以用枚举为整型常量提供作
用域为整个类的符号名称。也就是说,可以这样开始Bakery声明:

        class Bakery        {        private:        enum {Month = 12};        double costs[Month];        ...

注意,用这种方式声明枚举并不会创建类数据成员,也就是说所有对象中都不包含枚举。由于这里使用枚举只是
为了创建符号常量,并不打算创建枚举类型变量,因此不需要提供枚举名。
        第二,使用关键字static:

        class Bakery        {        private:        static const int Month = 12;        double costs[Month];        ...

这将创建一个名为Month的常量,该常量与其他静态变量存储在一起,而不是存储在对象中。因此只有一个Month
常量,被所有Bakery对象共享。



                                             
0 0