继承小节相对来说非常重要,因为继承多态和封装是面向对象编程的三大特性。
继承(inheritance) 机制是面向对象程序设计是代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行拓展,增加功能,这样产生新的类,叫做派生类。
继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触到的复用是函数层次的复用,但是继承是类设计层次的复用。
现在先举一个例子:
class Person{
public:void Print(){cout << "name:" << name_ << endl;cout << "age:" << age_ << endl;}
protected:string name_ = "ZS";int age_ = 18;
}class Student : public: Person{
protected:int stuId_;
};
定义格式:
class DerivedClass : public BaseClass
继承方式有三种,public、protected、private继承,和访问限定符相对。这三种继承方式的区别是基类成员在派生类中的访问权限。
类成员/继承方式 | public继承 | protected继承 | private继承 |
---|---|---|---|
基类的public成员 | 派生类的public成员 | 派生类的protected成员 | 派生类的private成员 |
基类的protected成员 | 派生类的protected成员 | 派生类的protected成员 | 派生类的private成员 |
基类的private成员 | 在派生类中不可见 | 不可见 | 不可见 |
class Person{
protected:string name_;string sex_;int age_;
};
class Student : public Person
{
public:int id_;
};
void Test(){Student sobj;//1. 子类可以赋值给父类对象/指针/引用Person pobj = sobj;Person* pp = &sobj;Person& rp = sobj;//2. 基类对象不能赋值给派生类对象sobj = pobj;//3. 基类的指针可以通过强制类型转换赋值给派生类的指针pp = &pobj;Student* ps1 = (Student*) pp;
}
举个例子:
class Person{
protected:string name_;string sex_;int age_;
public:void func(){cout << "func()" << endl;}
};
class Student : public Person
{
public:int id_;string name_;public:void func(int i){cout << "func(int i)" << endl;}
};
//可以发现Student 和 Person类中都有name_ 成员,这时会构成隐藏,在子类中如果cout<< name_ ,输出的是子类成员的name_.
//如果想访问父类成员的name_,使用:Person::name_.//可以发现Student 和 Person类中都有func 成员函数,但是因为不在同一个作用域中,所以不构成重载。
//但是因为二者同名,构成隐藏。也就是说如果直接调用父类中的func()函数,不能调用到。
友元关系不能继承,也就是说基类的友元函数不能访问子类的私有和保护成员。
如果基类定义一个static 静态成员,则整个 继承体系中 只有一个这样的成员,无论派生出多少个子类,都只有一个static 成员实例。
单继承:一个子类只有一个直接父类的继承关系。
多继承:一个子类有两个或以上直接父类的继承关系。
菱形继承:多继承的一种特殊情况。
菱形继承的问题:数据冗余和二义性。
因为在上面的例子中,Assistant 创建出的对象,Person 成员会有两份,所以会造成数据冗余和二义性。
解决问题:虚拟继承。
如果在Student 和Teacher 在继承Person时使用虚拟继承,就可以解决问题。注意,虚拟继承只适用于这种菱形继承的场景,如图。
虚拟继承可以解决数据冗余和二义性。原理是:
通过使用虚拟继承,不存放冗余数据,而是放了虚基表的指针,这个虚基表中存放了偏移量,通过偏移量可以找到数据(原来重复的数据),这个数据分属于不同的父类(Student 和Teacher)。就完成了虚拟继承。因为确定了这个成员到底继承自哪个父类。
多继承是C++ 语法复杂的体现。正因为多继承,才有菱形继承,正因为有菱形继承,才有菱形虚拟继承。所以不建议设计出多继承,复杂度提升,性能下降。
多继承是C++的缺陷。
继承和组合:
优先使用对象组合而不是类继承。
组合和继承的代码例子
//继承
class PeopleInfo{
public:int age_;string name_;
};
class TeacherInfo : public PeopleInfo
{
public:int teaId_;
}
//组合
class InformationSheet{
private:vector ppInfo_;...
}
本小节完。注意继承和多态的重要性,所以我们应该着重训练这方面的题目,加深理解。