偶然通过某个学习群得知了一道题目,因此而复习了C++面向对象的有关知识。不足之处,请指正。 /********** Inheri.h **********/ #include <iostream> using namespace std; /********************************************************************* *******公有派生:派生类对象包含基类对象,基类公有成员成为 派生类的公有成员,私有成员也成为派生类的一部分,但只能通 过基类的共有和保护方法访问。 **********************************************************************/ class A { public: A() { cout<<"A::A()"<<endl; } virtual ~A()//为何需要虚拟析构函数?虽然这好像并不需要。但是,这是必 //要的习惯。如Parent* p = new Child;delete p; //它能够保证正确的析构序列,即先析构子类对象再析构基类对象 //(与构造函数相反),否则对象只析构基类对象, //子类对象则没有释放 { cout<<"A::~A()"<<endl; } }; class B:public A { public: B():c(0)//公有继承的构造方法:不调用基类构造方法,程序将使用默认的基类构 //造方法。显式调用基类构造方法可以初始化继承自基类的私有变量; //还可以使用成员初始化列表对成员变量进行初始化(如本例对c的初始化) { cout<<"B::B()"<<endl; fun(); } virtual ~B()//为何需要虚拟析构函数?——同上 { cout<<"B::~B()"<<endl; } virtual void fun() { cout<<"B::fun"<<endl; } virtual void test(int a=10)//虚函数有何特性? { cout<<"a= "<<a<<endl; } private: char c; }; class C:public B { public: C():i(0)//派生类构造函数:基类对象首先被创建;派生类应当将(成员初始化列表) //基类信息传递给基类构造函数; //派生类构造函数应初始化派生类新增的数据成员 { cout<<"C::C()"<<endl; } ~C() { cout<<"C::~C()"<<endl; } void fun() { cout<<"C::fun"<<endl; } void test(int a=20) { cout<<"a= "<<a<<endl; } private: int i; }; /*** 1.派生类对象可以使用基类的公有方法和保护方法 2.基类指针可以在不进行显式类型转化的情况下指向派生类对象,基类指针只能调用基类方法 3.基类引用可以在不进行显式类型转化的情况下引用派生类对象,基类引用只能调用基类方法 同一方法在基类和在派生类表现的行为不同,其行为取决于调用该方法的对象,这种复杂的行 为称为多态。 1.在派生类中重新定义基类方法。 2.基类方法声明virtual,虚方法,如果方法是通过引用或指针而不是对象调用的,它将确定使 用哪一种方法: 使用virtual,程序根据引用类型或指针类型指向的对象选择方法,类似C#中的覆盖; 不使用virtual,程序根据引用类型或指针类型选择方法,类似C#中的隐藏; 简言之,virtual 使得子类方法 Override 基类方法。 ****/ /********** main.cpp **********/ #include "Inheri.h" int main() { cout<<"===Construct A==="<<endl; A *a=new C; cout<<"===Construct B==="<<endl; B *b=new C; cout<<"===Satrt Work==="<<endl; b->test(); cout<<"Size of A is "<<sizeof(A)<<endl; //用类创建的对象的内存空间是如何分配的?这个也是刚刚看到的。内容好多, //参考http://blog.csdn.net/guogangj/archive/2008/01/11/2036785.aspx,慢慢看,耐心看。 cout<<"Size of B is "<<sizeof(B)<<endl; cout<<"Size of C is "<<sizeof(C)<<endl; cout<<"==Delete b=="<<endl; delete b; cout<<"==Delete a=="<<endl; delete a; return 0; } /********************************************************************** *******在编译过程中进行的联编(bind),称为静态联编(早期联编)。 *******编译器在运行时生成选择虚方法的代码,这些代码用来选择正确的虚方法, 称为动态联编(晚期联编)。 编译器对废墟方法使用静态联编;编译器对虚方法使用动态联编。非虚函数的效率 比虚函数稍高,但不具备动态联编的能力。 编译器处理虚函数的方法:为每个对象怎家一个隐藏成员,用以保存一个指向函数 地址数组的指针。该数组称为虚函数表。虚函数表存储了为类对象进行声明的虚函数 的地址,额外开销为一个字。 构造函数不能是虚方法,无意义。 为基类定义虚拟析构函数。 友元不能使虚函数。 *********************************************************************/ 执行结果: