看完C++Primer的第十二章,现简单总结一下:
类的思想:数据抽象与封装。
数据封装:指的是提供的接口与接口的实现是分离的,也就是说在使用接口时,只需要知道该接口的功能,而不必关心细节。
封装:显然类将若干的数据成员封装在一起,其次,函数也是一种封装,是将一系列操作封装起来。
下面开始写类中的成员。
本章中的类是有关键字struct或者是class来定义的。
类只有在定义完成之后才能定义它的对象,但是在类中可以定义该类的指针和引用。
切记:在类的声明与定义之间是不能定义该类的对象的。
由类定义对象时,才会为创建的对象分配空间。各个对象之间是相互独立的,各自有一套自己的数据(static除外)。
数据成员的类型:
由访问控制机制,可以有private,public,protected。
由数据本身的性质(暂且这么说),有static与非static的。简言之,static成员是类自己的东西,是独一份的,不会分给对象的。
注:static成员是类自己的,因此不会被单个对象拥有,因此不能使用this指针对其进行访问。
既然如此,我们就需要定义函数来操纵这样特殊的static变量,那就是static成员函数。
还有一类更加特殊的成员变量,那就是const static成员,类在定义对象之前是不能被初始化的,但是const static 成员可以直接写死在类的定义之中。
例如:
class MyClass{ private: static const int _size = 7; int number[_size]; //... public: //other member };
由于该变量在类中已经制定了它的初始值,也就是说在类中是对_size的声明,并非定义,因此在类定义外还应该定义,但是就不需要指定初始值了。像这样:
const int MyClass::_size;
更值得一提的是,static成员打破了“定义在声明之后”这一说(自己为了便于记忆),因为可以在类的定义中,static成员变量竟然可以是该类的对象。例如:
class MyClass{ public: //... private: static MyClass my1; MyClass my2; // error };
上例中,my2的定义是错误的,在类未定义完成之前不能定义该类的非静态对象。
最后一点,由于static是类自己的,因此类的static变量可以作为类的成员函数的实参值。
总之:static成员变量是类自己的,是独一份的。各个对象只能通过类来操作它。
下面是成员函数:
首先,类的成员函数都有一个隐含的形参,那就是调用该函数的对象,用this指针来表示。一般情况下,在成员函数中使用成员变量时不需要显式的使用this指针,但是有些时候,需要返回对象本身的引用或者指针的时候,不要忘记有形参this。
成员函数也有const与非const之分,const对象只能使用const成员,非const成员则都可以使用,当然根据函数匹配的原则,还是会优先使用非const。
这里似乎很好的解释了一个我的疑惑:
那就是形参是否是const不能作为重载函数,但是如果函数的参数是引用或者指针
的时候,形参是否是const是可以实现函数重载的,那么由于调用它的对象的const或者非const,使得this指针有了const与非const之分,因此可以重载。
mutable是个神奇的词语。成员变量如果被声明是mutable的话,那么无论是怎样的对象(const与否),那么该变量随时随地都可以被修改。
随地!!是指即使在const成员函数中,依然如此。
接下来是类最重要的函数:构造函数。
要定义对象,构造函数是必须的。如果没有显式定义构造函数的话,编译器会自动生成一个默认的构造函数。
但是,如果一旦用户定义了构造函数,则编译器就不会再管构造函数的事儿了。
谈到构造函数,参数初始化列表是一个很重要的话题,列表的名字起的很好,初始化!!这里不是赋值,是初始化。
值得一提的是,在进入构造函数之前,所有的变量就会自己初始化(参考初始化规则),但是如果数据成员没有默认构造函数,或者是const成员以及引用成员时,就必须使用初始化列表,对他们来说,初始化列表是唯一的机会!!
注:成员初始化的顺序与定义的顺序一致,与在初始化列表中的顺序无关。
友元:可以将类、函数、其他类的成员函数声明为友元。该友元函数可以访问该类的成员变量。
最后,要提到的是类的作用域:
类的作用域可以分三个层次来理解,成员函数本身(如果是成员函数的话),类定义体内,定义该类的语句块,全局。
按照上述顺序对类的成员中用到的名字进行解析,如果在前面层找到了,就不再进入下一层了。