c++11继承二
-
继承与友元
友元关系不能继承,基类友元不能访问子类私有和保护成员
class Student; class Person { public: friend void print(const Person&, const Student&); protected: string name_{"yker"}; }; class Student : public Person { public: int num_{2}; protected: int id_; }; void print(const Person& p, const Student& s) { cout << p.name_ << s.name_ << s.num_ << endl; }
从例子可以看到 print函数中s对象并不能访问id_成员,原因是id_成员是保护的,相反num_可以被访问
-
继承与静态成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生多少个子类,都只有一个static成员
class Person { public: Person() { ++count_; } static int count_; }; int Person::count_ = 0; class Student : public Person { private: int id_; }; void test3() { Student s1; Student s2; Student s3; cout << Person::count_ << endl; // 3 Student::count_ = 0; cout << Person::count_ << endl; // 0 }
可以看出count_只有一份
-
多继承
一个子类有两个或以上直接父类时称这个继承关系为多继承
菱形继承是多继承的一种特殊情况
class Person { public: Person() { ++count_; } static int count_; }; int Person::count_ = 0; class Student : public Person { private: int id_; }; class Base { public: int id_{0}; }; class A : public Base { private: int flag_{1}; }; class B : public Base { private: int bang_{2}; }; class C : public A, public B { private: int self_{3}; }; void test4() { C c; c.id_ = 2; // 编译错误 c.A::id_ = 2; // 正确 }
对象模型:
由于对象c中有两个继承自Base类的id_成员变量,当我们对其进行初始化或赋值时,就会产生二义性, 编译器并不知道该向哪个id初始化赋值, 所以在对其进行初始化必须带上类名访问虽然解决了数据二义性但是数据冗余仍然存在,所以出现了虚继承
-
虚继承
class Base { public: int id_{ 0 }; }; class A : public Base { public: int flag_{ 1 }; }; class B : public Base { public: int bang_{ 2 }; }; class C : public A, public B { public: int self_{ 3 }; }; void test4() { C c; c.A::id_ = 1; c.B::id_ = 2; c.bang_ = 3; c.flag_ = 4; c.self_ = 5; }
菱形继承的对象模型
菱形虚继承的对象模型
通过对象模型内存布局可以得出,c对象将Base对象中的成员id_放在了对象组成的最下面,这个Base属于A和B,A和B通过各自的指针指向虚基表,虚基表中存的偏移量,A和B的地址加上偏移量就能找到Base
-
-
继承与组合
- public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象
- 组合是一种is-a的关系。假设B组合A,每个B对象中都有一个A对象
- 优先使用组合,而不是继承,破坏分装性
- 实现多态要用继承
于A和B,A和B通过各自的指针指向虚基表,虚基表中存的偏移量,A和B的地址加上偏移量就能找到Base*
-
继承与组合
- public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象
- 组合是一种is-a的关系。假设B组合A,每个B对象中都有一个A对象
- 优先使用组合,而不是继承,破坏分装性
- 实现多态要用继承