继承 C++
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
继承的语法
class Student : public Person中,Student是派生类,public是继承方式,Person是基类。
继承基类成员访问方式的变化
类成员/继承方式 | public继承 | protected继承 | private继承 |
---|---|---|---|
基类的publi成员 | 派生类的public成员 | 派生类的protected成员 | 派生类的private成员 |
基类的protected成员 | 派生类的protected成员 | 派生类的protected成员 | 派生类的private成员 |
基类的private成员 | 在派生类中不可见 | 在派生类中不可见 | 在派生类中不可见 |
在实际运用中一般使用的都是public继承,很少用到protected继承和private继承
基类和派生类对象赋值转换
派生类对象可以赋值给基类的对象/指针/引用,但基类对象不能赋值给派生类对象。派生类对象的赋值转换是将派生类中基类的部分切下来赋值给基类。
class Person
{
protected :
string _name; // 姓名
string _sex; // 性别
int _age; // 年龄
};
class Student : public Person
{
public :
int _No ; // 学号
};
void Test ()
{
Student sobj ;
// 1.子类对象可以赋值给父类对象/指针/引用
Person pobj = sobj ;
Person* pp = &sobj;
Person& rp = sobj;//此时这三者都不包含_No变量
}
继承中的隐藏
子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。但是也能通过基类:基类成员来显式访问。成员函数只需要函数名相同就构成隐藏。在实际的运用中最好不要定义同名的成员。
继承后子类的构造和析构
子类的构造函数会先调用基类的构造函数,在调用自己的构造函数,子类的析构函数会在被调用完成后自动调用基类的析构函数。
class Person
{
public :
Person(const char* name = "peter")
: _name(name )
{
cout<<"Person()" <<endl;
}
~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()
{
cout<<"~Student()" <<endl;
}
protected :
int _num ; //学号
};
//此时构建一个Student对象后的运行结果为:
//Person()
//Student()
//~Student()
//~Person()
继承与友元
友元关系不能继承,基类友元不能访问子类私有和保护成员。
若基类定义了static静态成员,则整个继承体系中只有一个这样的成员。
菱形继承
定义:两个子类继承同一个基类,然后一个子类同时继承这两个子类。
问题:数据冗余和二义性
解决方法:虚继承
在实际中一定不要设计出菱形继承,否则在复杂度上及性能上都有问题。
继承和组合
优先使用对象组合,而不是继承。因为组合的耦合度低,继承的耦合度高,而耦合度越低,代码维护性越好。