面向对象的四大特点:抽象、封装、继承、多态。其中抽象、封装分别对应类、对象。
继承指的是在既有类的基础上产生新的类。
派生类的生成过程
不能继承的基类特征
operator new|delete运算符operator=赋值运算符三种继承方式
总结:派生类的访问权限,不管以什么继承方式
派生类构造函数的特点
例如:
class Derived: public Base {
public:
Derived(long base, long derived)
: Base(base) // 显示调用基类的构造函数
, _derived(derived)
{}
long _derived;
};
派生类构造函数的调用顺序
与对象创建顺序相反,在执行派生类析构函数时,基类析构函数会被自动调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数
单即继承和多基继承的派生类构造函数功能没有本质不同,首先要执行所有基类的构造函数,再执行派生类构造函数初始化列表中的其他内容,最后是构造函数体。
注意:各基类构造函数的执行顺序与其在初始化表中的顺序无关,而是由定义派生类时指定的基类顺序决定的。
析构函数的执行顺序同样是与构造函数的执行顺序相反。但在使用多基继承过程中,会产生两种二义性。
A::print()菱形继承

class B: virtual public A // 1个虚基指针 + 数据
class C: virtual public A // 1个虚基指针 + 数据
class D: public B, public C // 2个虚基指针 + 数据
派生类适应于基类,派生类对象能直接用于基类对象的场景,具体形式为:
// 1、派生类的对象赋值给基类的对象
base = derived;
base.operator=(derived);
// 2、基类的引用绑定到派生类的对象
const Base &ref = derived;
// 3、基类的指针指向派生类的对象
Base *pbase = &derived;
向上转型与向下转型
Base *pbase = &derived;例:
// 不安全的向下转型:直接将 base 指针转换为 derived 指针
// base 8B, derived 16B,新的指针多控制了 8B,可能存在内存越界的问题
Derived *pderived = static_cast<Derived *>(&base);
// 安全的向下转型
Base *pbase = &derived; // base 指针指向派生类对象,先向上转型
Derived *pderived = static_cast<Derived *>(pbase); // 再向下转型
原则:先构造基类部分,后构造派生类部分
派生类对象的复制控制
测试代码:
#include
#include
using std::cout;
using std::endl;
class Base
{
public:
Base()
: _pbase(nullptr)
{
cout << "Base()" << endl;
}
Base(const char *pbase)
: _pbase(new char[strlen(pbase) + 1]())
{
cout << "Base(const char *)" << endl;
strcpy(_pbase, pbase);
}
Base(const Base &rhs)
: _pbase(new char[strlen(rhs._pbase) + 1]())
{
cout << "Base(const Base &)" << endl;
strcpy(_pbase, rhs._pbase);;
}
Base &operator=(const Base &rhs) {
cout << "Base &operator=(const Base &)" << endl;
if(this != &rhs) {
delete [] _pbase;
_pbase = nullptr;
_pbase = new char[strlen(rhs._pbase) + 1]();
strcpy(_pbase, rhs._pbase);
}
return *this;
}
~Base() {
cout << "~Base()" << endl;
if(_pbase)
{
delete [] _pbase;
_pbase = nullptr;
}
}
friend std::ostream &operator<<(std::ostream &os, const Base &rhs);
private:
char *_pbase;
};
std::ostream &operator<<(std::ostream &os, const Base &rhs) {
if(rhs._pbase) {
os << rhs._pbase;
}
return os;
}
class Derived
: public Base
{
public:
Derived()
: Base()
, _pderived(nullptr)
{
cout << "Derived()" << endl;
}
Derived(const char *pbase, const char *pderived)
: Base(pbase)
, _pderived(new char[strlen(pderived) + 1]())
{
cout << "Derived(const char *)" << endl;
strcpy(_pderived, pderived);
}
Derived(const Derived &rhs)
: Base(rhs) // 显示调用基类的构造函数
, _pderived(new char[strlen(rhs._pderived) + 1]())
{
cout << "Derived(const Derived &)" << endl;
strcpy(_pderived, rhs._pderived);
}
Derived &operator=(const Derived &rhs) {
cout << "Derived &operator=(const Derived &)" << endl;
if(this != &rhs) {
Base::operator=(rhs); // 显示调用基类的赋值运算符函数
delete [] _pderived;
_pderived = nullptr;
_pderived = new char[strlen(rhs._pderived) + 1]();
strcpy(_pderived, rhs._pderived);
}
return *this;
}
~Derived() {
cout << "~Derived()" << endl;
if(_pderived) {
delete [] _pderived;
_pderived = nullptr;
}
}
friend std::ostream &operator<<(std::ostream &os, const Derived &rhs);
private:
char *_pderived;
};
std::ostream &operator<<(std::ostream &os, const Derived &rhs) {
// const引用指向const对象,基类的引用绑定到派生类的对象
const Base &ref = rhs;
// <<重载(基类、派生类)
os << ref << ", " << rhs._pderived;
return os;
}
int main() {
Derived d1("hello", "world");
cout << "d1 = " << d1 << endl;
cout << endl;
Derived d2 = d1;
cout << "d1 = " << d1 << endl;
cout << "d2 = " << d2 << endl;
cout << endl;
Derived d3("hubei", "wuhan");
cout << "d3 = " << d3 << endl;
d3 = d1;
cout << "d1 = " << d1 << endl;
cout << "d3 = " << d3 << endl;
return 0;
}