继承是面向对象复用的重要手段。通过继承定义一个类,继承是类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。
三种继承关系:public、protected、private
三种继承关系下基类成员在派生类的访问关系变化。
public继承:基类的public成员仍为public成员、基类的protected仍为protected成员、基类的private成员不可见。
protected继承:基类的public变为protected、基类的protected变为protected、基类的private不可见。
private继承:基类的public变为private、基类的protected变为private、基类的private不可见。
#include <iostream> #include <string> using namespace std; class Person { public : void Display () { cout<< _name <<endl; } protected : string _name ; // 姓名 private : int _age ; // 年龄 }; //class Student : protected Person //class Student : private Person class Student : public Person { protected : int _num ; // 学号 }; int main() { Person p; p.Display(); Student s; s.Display(); return 0; }
总结:
1. 基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保
护成员。可以看出保护成员限定符是因继承才出现的。
2. public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
3. protetced/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情
况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能
访问)。
5. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6. 在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.
继承与转换--赋值兼容规则--public继承
1. 子类对象可以赋值给父类对象(切割/切片)
2. 父类对象不能赋值给子类对象
3. 父类的指针/引用可以指向子类对象
4. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
class Person { public : void Display () { cout<<_name <<endl; } protected : string _name ; // 姓名 }; class Student : public Person { public : int _num ; // 学号 }; void Test () { Person p ; Student s ; // 1.子类对象可以赋值给父类对象(切割 /切片) p = s ; // 2.父类对象不能赋值给子类对象 //s = p; 3.父类的指针/引用可以指向子类对象 Person* p1 = &s; Person& r1 = s; // 4.子类的指针/引用不能指向父类对象(可以通过强制类型转换完成) Student* p2 = (Student*)& p; Student& r2 = (Student&) p; } int main() { Test(); return 0; }
继承体系中派生类的六个默认成员函数
class Person { public : Person(const char* name) : _name(name ) { cout<<"Person()" <<endl; } Person(const Person& p) : _name(p ._name) { cout<<"Person(const Person& p)" <<endl; } Person& operator =(const Person& p ) { cout<<"Person operator=(const Person& p)"<< endl; if (this != &p) { _name = p ._name; } return *this ; } ~ Person() { cout<<"~Person()" <<endl; } protected : string _name ; // 姓名 }; class Student : public Person { public : Student(const char* name, int num) : Person(name ) , _num(num ) { cout<<"Student()" <<endl; } Student(const Student& s) : Person(s ) , _num(s ._num) { cout<<"Student(const Student& s)" <<endl ; } Student& operator = (const Student& s ) { cout<<"Student& operator= (const Student& s)"<< endl; if (this != &s) { Person::operator =(s); _num = s ._num; } return *this ; } ~Student() { cout<<"~Student()" <<endl; } private : int _num ; //学号 }; void Test () { Student s1 ("jack", 18); Student s2 (s1); Student s3 ("rose", 17); s1 = s3 ; } int main() { Test(); return 0; }
单继承&多重继承
1. 单继承--一个子类只有一个直接父类时称这个继承关系为单继承
2. 多继承--一个子类有两个或以上直接父类时称这个继承关系为多继承
菱形继承存在二义性和数据冗余的问题。
虚继承--解决菱形继承二义性和数据冗余问题。
1、--解决了在菱形体系中子类对象包含多份父类对象的数据冗余和浪费空间问题。
2--使用虚继承解决数据冗余问题也带来了性能上的损耗。