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

(一)  散知识

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对象共享。



 

猜你喜欢

转载自blog.csdn.net/u012481976/article/details/54426183
今日推荐