继承(二)
-
构造函数
- 析构函数
- =运算符【由于它的功能跟构造函数类似,所以也不能被继承】
- 基类的构造函数不被继承,派生类中需要声明自己的构造函数。
-
声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化(调用基类构造函数完成)。
-
派生类的构造函数需要给基类的构造函数传递参数。
下面用代码来说明下:
#include <iostream> using namespace std; class Base { public: Base() { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; }; class Derived : public Base { public: Derived() { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; }; int main(void) { Derived d; cout<<d.b_<<" "<<d.d_<<endl; return 0; }
编译运行:
从结果中可以发现,是先构造基类,再构造派生类的~
#include <iostream> using namespace std; class Base { public: Base() { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; }; class Derived : public Base { public: Derived(int d) : d_(d) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; }; int main(void) { Derived d(100); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
其结果:
派生类中的成员变量已经初始化值了,但是基类的还没有,下面给基类成员变量初始化:
#include <iostream> using namespace std; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; }; class Derived : public Base { public: Derived(int d) : d_(d) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; }; int main(void) { Derived d(100); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
编译:
报错了,这是为什么呢?
这是由于派生类中如果没有明确指定调用基类的构造函数,则默认就是调用基类的默认构造函数,而Base类中目前没有提供默认构造函数,所以编译不通过了:
所以解决办法很简单,主动调用带参数的Base构造函数既可:
#include <iostream> using namespace std; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
编译运行:
下面再来看一下这种情况:
#include <iostream> using namespace std; class ObjectD { public: ObjectD() { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } }; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_;//类成员对象 }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
看一下对象构造的顺序:
可以发现顺序如下:基类构造->类成员构造->派生类构造;而销毁的顺序刚好相反。
如果基类也持有一个对象成员,那又该如何呢?
#include <iostream> using namespace std; class ObjectB { public: ObjectB() { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } }; class ObjectD { public: ObjectD() { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } }; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
编译运行:
从中可以发现:先调用基类的对象成员构造函数、然后调用基类构造函数、再然后是派生类的对象成员的构造函数、最后是派生类自身的构造函数。析构的次序则相反。
如果说类当中对象成员不止有一个,则按声明的次序来进行构造。
下面继续看:
#include <iostream> using namespace std; class ObjectB { public: ObjectB() { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } }; class ObjectD { public: ObjectD(int objd) : objd_(objd) {//现在没有默认构造函数了 cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } int objd_; }; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
编译:
这是在意料之中的事~在初始化列表中也需要对对象成员进行构造:
#include <iostream> using namespace std; class ObjectB { public: ObjectB() { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } }; class ObjectD { public: ObjectD(int objd) : objd_(objd) { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } int objd_; }; class Base { public: Base(int b) : b_(b) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b), objd_(111) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
这时就可正常编译了。同样的在基类中也得这样做:
#include <iostream> using namespace std; class ObjectB { public: ObjectB(int objb) : objb_(objb) { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } int objb_; }; class ObjectD { public: ObjectD(int objd) : objd_(objd) { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } int objd_; }; class Base { public: Base(int b) : b_(b), objb_(222) { cout<<"Base ..."<<endl; } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b), objd_(111) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; return 0; }
下面回顾一下之前所学的哪些情况只能在类的构造函数的初始化列表当中进行初始化:
①、const成员:const int n = 100;
②、引用成员:
int n = 200;
int& rn = n;
③、类的对象成员没有默认构造函数的时候,只能够在类的构造函数初始化列表中调用该对象的构造函数进行初始化。
④、基类没有默认构造函数时,基类的构造函数要在派生类构造函数列表当中调用。
下面来看一下拷贝构造函数的情况:
编译一下:
从上面错误来看在基类的拷贝构造函数中,也需要调用ObjectB的指定构造才行:
#include <iostream> using namespace std; class ObjectB { public: ObjectB(int objb) : objb_(objb) { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } int objb_; }; class ObjectD { public: ObjectD(int objd) : objd_(objd) { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } int objd_; }; class Base { public: Base(int b) : b_(b), objb_(222) { cout<<"Base ..."<<endl; } Base(const Base& other) : objb_(other.objb_), b_(other.b_){ } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b), objd_(111) { cout<<"Derived ..."<<endl; } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; Base b1(100); Base b2(b1); cout<<b2.b_<<endl; return 0; }
编译运行:
下面来看一下派生类的拷贝构造:
#include <iostream> using namespace std; class ObjectB { public: ObjectB(int objb) : objb_(objb) { cout<<"ObjectB ..."<<endl; } ~ObjectB() { cout<<"~ObjectB ..."<<endl; } int objb_; }; class ObjectD { public: ObjectD(int objd) : objd_(objd) { cout<<"ObjectD ..."<<endl; } ~ObjectD() { cout<<"~ObjectD ..."<<endl; } int objd_; }; class Base { public: Base(int b) : b_(b), objb_(222) { cout<<"Base ..."<<endl; } Base(const Base& other) : objb_(other.objb_), b_(other.b_){ } ~Base() { cout<<"~Base ..."<<endl; } int b_; ObjectB objb_; }; class Derived : public Base { public: Derived(int b, int d) : d_(d), Base(b), objd_(111) { cout<<"Derived ..."<<endl; } Derived(const Derived& other) : d_(other.d_), objd_(other.objd_), Base(other) { } ~Derived() { cout<<"~Derived ..."<<endl; } int d_; ObjectD objd_; }; int main(void) { Derived d(100, 200); cout<<d.b_<<" "<<d.d_<<endl; Base b1(100); Base b2(b1); cout<<b2.b_<<endl; Derived d2(d); return 0; }
正常编译,所以拷贝构造函数实际上也是构造函数,所以两者的初始化列表要做的事一样~
①、友元关系不能被继承,下面举个例子:
A是B的友元类
C是A的派生类
那么C不是B的友元类
②、友元关系是单向的。
③、友元关系是不能被传递的,下面举个例子:
A是B的友元类
B是C的友元类
那么A不是C的友元类
这里就不写代码来验证了,比较简单。
#include <iostream> using namespace std; class Base { public: static int b_; }; int Base::b_ = 100; class Derived : public Base { }; int main(void) { Base b; Derived d; cout<<Base::b_<<endl; cout<<b.b_<<endl;//不推荐用对象访问静态成员 cout<<Derived::b_<<endl; cout<<d.b_<<endl;//不推荐用对象访问静态成员 return 0; }
编译运行:
都可以正常访问,所以就无所谓继承啦~