一、基本概念
- 一个基类可以派生多个派生类,一个派生类也可以由多个基类派生而成
- 继承
- 单一继承
- 多重继承
- 继承方式(缺省默认:private)
- public
- private
- protected
公有继承 | 保护继承 |
私有继承 | |
公有成员 |
public | protected | private |
保护成员 | protected | protected | private |
私有成员 | 不可见 | 不可见 | 不可见 |
- 基类的 private 成员不可以被继承
二、派生类的构造及析构
#include <iostream> using namespace std; class a1 { public: a1() { cout << "a1 Constructor called" << endl; } ~a1() { cout << "a1 Destructor called" << endl; } }; class a2 { public: a2() { cout << "a2 Constructor called" << endl; } ~a2() { cout << "a2 Destructor called" << endl; } }; class Derived : public a1, public a2 { public: Derived() { cout << "Derived Constructor called" << endl; } ~Derived() { cout << "Derived Destructor called" << endl; } }; int main() { Derived obj; return 0; }
输出结果:
a1 Constructor called
a2 Constructor called
Derived Constructor called
Derived Destructor called
a2 Destructor called
a1 Destructor called
在定义一个派生类对象时,构造函数的调用顺序:
基类 >>> 派生类对象成员(按定义顺序) >>> 派生类
析构函数调用顺序恰好相反
//将 Derived 修改如下 class Derived : public a2 { private: a1 obj1; public: Derived() { cout << "Derived Constructor called" << endl; } ~Derived() { cout << "Derived Destructor called" << endl; } };
a2 Constructor called
a1 Constructor called
Derived Constructor called
Derived Destructor called
a1 Destructor called
a2 Destructor called
有参情况
- 派生类只需要负责直接基类构造函数的调用
- 如果基类构造函数不需要提供参数,则无需在初始化列表中给出
- 创建对象构造函数的调用顺序与声明顺序有关,而非在初始化列表中的顺序
- 其他初始化项包括对象成员,常成员和引用成员
示例
#include <iostream> using namespace std; class Base { private: static int count; int x; public: Base(int i) { x=i; cout<<"Base constructor called"<<count++<<endl; } void display() { cout<<"x = "<<x<<endl; } }; class Derived : public Base { private: Base b; public: Derived (int i): Base(i),b(i) { cout<<"Derived constructor called"<<endl; } }; int Base::count=0; int main() { Derived d(3); d.display(); return 0; }
多重继承示例
#include <iostream> using namespace std; class Grand { private: int a; public: Grand(int n):a(n) { cout << "Grand c,a=" << a << endl; } ~Grand() { cout << "Grand d" << endl; } }; class Father:public Grand { private: int b; public: Father(int n1,int n2):Grand(n1),b(n2) { cout << "Father c,b=" << b << endl; } ~Father() { cout << "Father d" << endl; } }; class Mother { private: int c; public: Mother(int n):c(n) { cout << "Mother c,c=" << c << endl; } ~Mother() { cout << "Mother d" << endl; } }; class Child:public Father,public Mother { private: int d; public: Child(int n1,int n2,int n3,int n4):Father(n4,n3),Mother(n2),d(n1) { cout << "Child d=" << d << endl; } ~Child() { cout << "Child d" << endl; } }; int main() { Child c(1,2,3,4); return 0; }
Grand c,a=4
Father c,b=3
Mother c,c=2
Child d=1
Child d
Mother d
Father d
Grand d
三、同名冲突
基类与派生类的同名冲突
同名覆盖原则:新成员名称与基类某个成员同名时,若未加任何特殊标识,访问派生类中新定义的同名成员
需要访问基类:使用 “基类名::” 进行限定
- 通过派生类的指针或引用,访问的是派生类的同名成员(同名覆盖√)
- 基类指针/引用,访问基类同名成员
#include <iostream> using namespace std; class Base { public: int a; Base(int x) { a = x; } void Print() { cout << "Base::a = " << a << endl; } }; class Derived : public Base { public: int a; //欸这里也有个a耶 Derived(int x, int y) : Base(x) { a = y; Base::a *= 2; } void Print() { Base::Print(); cout << "Derived::a = " << a << endl; } }; void Test1(Base& b) { b.Print(); } void Test2(Derived& d) { d.Print(); } int main() { Derived d(200, 300); d.Print(); d.a = 400; d.Base::a = 500; d.Base::Print(); Base* pb; pb = &d; pb->Print(); Test1(d); Derived *pd; pd = &d; pd->Print(); Test2(d); return 0; }
多重继承中直接基类的同名冲突
通过域解析符解决
#include <iostream> using namespace std; class Base1 { protected: int a; Base1(int x) { a = x; cout<<"Base1 a="<<a<<endl; } void Print() { cout << "Base::a = " << a << endl; } }; class Base2 { protected: int a; public: Base2(int x) { a = x; cout<<"Base2 a="<<a<<endl; } }; class Derived:public Base1, public Base2 { public: Derived(int x,int y):Base1(x),Base2(y) { Base1::a *=2; Base2::a *=2; cout<<"Derived from Base1::a="<<Base1::a<<endl; cout<<"Derived from Base2::a="<<Base2::a<<endl; } }; int main() { Derived d(10,20); return 0; }
共同祖先基类引发的同名冲突
- 域解析符
- 虚基类
虚基类
virtual 确保虚基类最多被调用一次
#include <iostream> using namespace std; class Base { protected: int a; public: Base (int x):a(x) { cout<<"Base a="<<a<<endl; } ~Base () { cout<<"Base destructor"<<endl; } }; class Base1 : public virtual Base { protected: int b; public: Base1(int x,int y):Base(y),b(x) { cout<<"Base1 from Base a="<<a<<endl; cout<<"Base1 b="<<b<<endl; } }; class Base2 : public virtual Base { protected: int c; public: Base2(int x,int y):Base(y),c(x) { cout<<"Base2 from Base a="<<a<<endl; cout<<"Base2 c="<<c<<endl; } }; class Derived : public Base1, public Base2 { public: Derived(int x,int y):Base1(x,y),Base2(2*x,2*y),Base(3*x) { cout<<"a="<<a<<endl; cout<<"Base::a="<<Base::a<<endl; cout<<"Base1::a="<<Base1::a<<endl; cout<<"Base2::a="<<Base2::a<<endl; cout<<"b="<<b<<endl; cout<<"c="<<c<<endl; } ~Derived () { cout<<"Derived destructor"<<endl; } }; int main() { Derived d(10,20); return 0; }
其中 Base 类只有一份复制
只有最后一层派生类对虚基类构造函数的调用发挥作用
创建一个对象,构造函数调用次序:
虚基类的构造函数
直接基类的构造函数
对象成员的构造函数
派生类自己的构造函数
四、赋值兼容规则
使公有派生类可以当作基类来使用
1. 派生类对象 -> 基类对象
2. 派生类对象地址 -> 基类指针
3. 派生类对象指针 -> 基类指针
3.派生类对象 -> 基类引用
#include <iostream> using namespace std; class Base { private: int b; public: Base(int x):b(x) {} int getB() { return b; } }; class Derived : public Base { private: int d; public: Derived(int x, int y):Base(x), d(y) {} int getD() { return d; } }; int main() { Base b(11); Derived d(22, 33); b = d; cout << "b.getB() = " << b.getB() << endl; Base *bp = &d; cout << "bp->getB() = " << bp->getB() << endl; Derived *dp = &d; Base *bp2 = dp; cout << "bp2->getB() = " << bp2->getB() << endl; Base &rb = d; cout << "rb.getB() = " << rb.getB() << endl; return 0; }