18、mutable变量 mutable允许const方法修改mutable修饰的变量; 比如在一个类中有数据成员: mutable int mNumAccess; const getValue(); 一般情况下类的const成员方法是不允许修改类的成员数据的,加上mutable将允许 const成员方法修改mNumAccess. 19、基于const重载一个方法 可以编写两个同名且参数也相同的方法,只不过其中一个为const另一个不是。如果,你提供了 一个const对象,编译器会调用const方法,如果,你提供一个非const对象,编译器将调用非const方法。 20、explicit关键字只能放在类定义中,而且只适用于仅有一个参数的构造函数; 21、类的方法和成员指针 在程序中一般不会出现方法和类成员的指针。不过,要记住重要的一点:对于一个指向非静态方法或成员的指针, 如果,没有对象就不能对其解除引用。因为,非静态的方法或成员只有通过一个对象的建立才可以使用,没有对象就不可以对其指针解除引用。 比如,你可能想把一个指向非静态方法的指针传递给一个诸如qsort()的函数(它需要一个函数指针),是不会成功的;必须先有 对象才行。 二、类的继承 22、访问限定符: 从子类的角度来看,超类中所有的public和protected的数据成员和方法都是可用的。 但是,子类不可以访问父类的private数据成员和方法。在实际应用中,往往把数据成员声明为protected,以便于进行扩展。 23、virtual,不要犹豫,将所有的超类成员函数声明为virtual,以便于子类进行覆盖。 在C++中必须使用virtual关键字才能保证超类中的方法能被子类正确覆盖。 作为一条经验,要把所有的方法都用virtual声明,包括析构函数,但不包括构造函数,来避免因遗漏关键字virtual而产生的相关问题。 例如: class Super { public: Super( ); virtual void someMethod( ); protected: int mProtectedInt; private: int mPrivateInt; }; class Sub:public Super { public: Sub( ); virtual void someMethod( ); virtual void someOtherMethon( ); }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (1) 如果在Super中someMethon()没有virtual声明,那么,则不能进行正确的覆盖: Sub mySub; Super& ref=mySub; ref.someMethon() //会调用子类Sub的someMethon(),而不是Super的someMethon() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (2)记住一点,即使超类的引用或者指针知道实际上它是一个子类,也不能调用在超类中未定义的子类或者成员。 下面的代码无法成功编译,因为Super并没有包含方法someOtherMethon(): Sub mySub; Super& ref=mySub; ref.someOtherMethon() //Error! can't do this ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (3)对于非指针、非引用的对象,则不具有这个特性(知道自己的实际类型),它不知道自己到底是那个子类。如下: Sub mySub; Super assignedObject=mySub; //assign Sub to Super; assignedObject.someMethon(); //将会调用Super的someMethon(),因为assignedObject不是指针也不是引用。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 注意: 超类指针或引用在引用子类时,子类仍然会保留它们覆盖的方法(exp:Code (1) )。而在强制转换为超类对像时, 子类会丧失它们独有的特性(exp:Code (3)) 。覆盖方法和子类数据的丢失称为切割 slicing。 如果把子类赋给其超类的指针或者引用,就不会发生切割问题。 24、多态 多态就是一个事物的不同形态。结合类和子类之间的继承来理解。 25、 构造函数的构造顺序 (1)如果有的话,首先构造基类 (2)非static数据成员按照声明的顺序 (3)执行构造函数体 析构函数的析构顺序 (1)调用子类的析构函数 (2)按照构造的逆序删除数据成员 (3)如果有父类,删除父类 注意:对于析构函数全部使用virtual关键字声明,把这作为一个经验。 #include <iostream> using namespace std; class Something { public: Something( ) {cout<<"2";} ~Something( ){cout<<"2";} //should be virtual,but it will work }; class Parent { public: Parent( ) {cout<<"1";} ~Parent( ){cout<<"1";} //BUG! make this virtual }; class Child:public Parent { public: Child( ){cout<<"3";} ~Child( ){cout<<"3";} //should be vritual ,but it will work protected: Something mDataMember; }; int main( ) { Parent* ptr=new Child( ); delete ptr; cout<<"/n"; return 0; } 结果: 如果去掉delete ptr;将输出“123”,证明堆上的空间不会自动释放; 如果不去掉delete;将输出“1231”,证明如果类的析构函数不声明为virtual,则调用会出现不如我们原来想象的那样。 如果不去掉delete,同时按照建议添加virtual,将输出“123321”. 26、向上类型强制转换和向下强制类型转换 类的继承层次上的关系是,父类在上,派生类在下; 向上强制类型转换:将子类转换成其父类;注意:要使用父类的指针或者引用来避免切割问题。 向下强制类型转换:将一个父类转成其子类;注意:只有在必须并且能保证使用动态类型转换(dynamic_cast)的时候才使用向下强制类型转换。 向下强制类型转换是一个让C++程序员挠头的点。 exp: void presumptuous(Super* inSuper) { Sub* mySub=static_cast<Sub*>(inSuper); //Proceed to access Sub methods on mySub } //这个函数是不推荐使用的 void lessPresumptuous(Super* inSuper) { Sub* mySub=dynamic_cast<Sub*>(inSuper); //use the dynamic_cast<> if(mySub!=NULL) { //Proceed to access Sub methods on mySub } } 27、抽象类 纯虚方法Pure virtual method是指在类中未显示定义的一种方法,直接函数“=0”即可。 包含有纯虚方法的类叫抽象类,纯虚方法就是告诉编译器,不可以生成此抽象类的实例对象。 这样就可以实现父类要对子类的行为提供支持,但是有不能实际定义这些行为的要求。 //这个例子展示了父类指针指向子类对象的情况 #include <iostream> using namespace std; class Super { public: Super( int proint=0,int priint=0 ): mProtectedInt( proint ),mPrivateInt( priint ) { } virtual void someMethod( ) { cout<<"This is class Super someMethod( )/n"; } protected: int mProtectedInt; private: int mPrivateInt; }; class Sub:public Super { public: Sub(int proint,int priint,int subint): Super( proint,priint ),mSubInt( subint ) { } virtual void someMethod( ) { cout<<"This is class Sub someMethod( )/n"; } virtual void someOtherMethod( ) { cout<<"This is class Sub someOtherMethod( ),Super class don't has/n"; } protected: int mSubInt; }; int main( ) { Super* mSuperPtr; Sub* mSubPtr; mSubPtr=new Sub( 2,3,4 ); mSubPtr->someMethod( ); mSubPtr->someOtherMethod( ); mSuperPtr=mSubPtr; mSuperPtr->someMethod( ); //可以 mSuperPtr->someOtherMethod( );//错误:父类指针不可以调用子类中独有的成员函数 return 0; } 编译器错误 gcc4.4.5 test.cpp: In function ‘int main()’: test.cpp:54:20: error: ‘class Super’ has no member named ‘someOtherMethod’