引言继承是面向对象编程的核心特性之一但很多初学者对继承的理解仅仅停留在“子类拥有父类的成员”这个层面。然而在实际开发中我们需要深入理解派生类对象在内存中是如何布局的基类对象和成员对象有什么区别多重继承会带来什么问题今天我将通过详细的内存模型分析和代码示例系统地讲解C继承中的高级特性。第一部分继承关系中对象的存储布局一、单继承的内存布局#include iostream using namespace std; class Base { private: int b1; int b2; public: Base() : b1(10), b2(20) {} virtual void func() { cout Base::func endl; } }; class Derived : public Base { private: int d1; int d2; public: Derived() : d1(100), d2(200) {} virtual void func() override { cout Derived::func endl; } }; int main() { Derived d; // 内存布局32位系统 // [vptr][b1][b2][d1][d2] // 4B 4B 4B 4B 4B 20B cout Derived size: sizeof(Derived) endl; // 输出20取决于虚表指针和对齐 return 0; }二、对象存储布局图解三、基类对象与成员对象的区别class Member { private: int m; public: Member(int val) : m(val) { cout Member构造: m endl; } ~Member() { cout Member析构: m endl; } }; class Base { private: int b; public: Base(int val) : b(val) { cout Base构造: b endl; } ~Base() { cout Base析构: b endl; } }; class Derived : public Base { // 基类子对象 private: Member m1; // 成员对象 Member m2; // 成员对象 public: Derived(int b, int m1v, int m2v) : Base(b), m1(m1v), m2(m2v) { cout Derived构造 endl; } ~Derived() { cout Derived析构 endl; } }; int main() { Derived d(10, 20, 30); return 0; } /* 输出顺序构造 Base构造: 10 ← 1. 基类子对象 Member构造: 20 ← 2. 成员对象按声明顺序 Member构造: 30 ← 3. 成员对象 Derived构造 ← 4. 派生类构造函数体 输出顺序析构完全相反 Derived析构 Member析构: 30 Member析构: 20 Base析构: 10 */关键区别类型构造时机析构时机内存位置基类子对象最先构造最后析构派生类对象内部成员对象按声明顺序构造按相反顺序析构派生类对象内部局部对象执行到定义处离开作用域栈上第二部分同名隐藏与作用域一、同名隐藏规则当派生类定义了与基类同名的成员时基类的成员会被隐藏。class Base { public: int value 10; void func() { cout Base::func() endl; } void func(int x) { cout Base::func(int): x endl; } }; class Derived : public Base { public: int value 100; // 隐藏基类的 value void func() { cout Derived::func() endl; } // 隐藏所有基类 func }; int main() { Derived d; cout d.value endl; // 100派生类成员 // cout d.Base::value endl; // 10通过作用域访问 d.func(); // Derived::func() // d.func(10); // 错误func(int) 被隐藏了 d.Base::func(10); // 正确显式调用基类版本 return 0; }二、重载与隐藏的区别场景行为说明基类重载函数派生类可继承所有重载版本都可用派生类定义同名函数隐藏所有基类版本无论参数是否相同使用using声明可引入基类重载using Base::func;class Derived : public Base { public: using Base::func; // 将基类的所有 func 引入当前作用域 void func() { cout Derived::func() endl; } }; // 现在 d.func(10) 可以正常调用第三部分赋值兼容规则一、基本规则派生类对象可以赋值给基类对象但反过来不行。class Base { public: int b; Base(int val 0) : b(val) {} }; class Derived : public Base { public: int d; Derived(int bv 0, int dv 0) : Base(bv), d(dv) {} }; int main() { Derived d(10, 20); Base b; // 1. 派生类对象赋值给基类对象切片 b d; // 只复制基类部分d.d 丢失 // 2. 派生类指针/引用赋值给基类指针/引用 Base* pb d; // 合法指向派生类对象的基类部分 Base rb d; // 合法 // 3. 反过来不行 // Derived* pd b; // 错误基类不能赋值给派生类 // d b; // 错误 return 0; }二、切片问题void printBase(Base b) { cout Base value: b.b endl; } void printBaseRef(Base b) { cout Base value: b.b endl; } int main() { Derived d(10, 20); printBase(d); // 传值发生切片丢失派生类部分 printBaseRef(d); // 传引用不发生切片保留派生类信息 return 0; }第四部分继承中的构造与析构一、构造和析构顺序class Grand { public: Grand() { cout Grand构造 endl; } ~Grand() { cout Grand析构 endl; } }; class Parent : public Grand { public: Parent() { cout Parent构造 endl; } ~Parent() { cout Parent析构 endl; } }; class Child : public Parent { public: Child() { cout Child构造 endl; } ~Child() { cout Child析构 endl; } }; int main() { Child c; return 0; } /* 输出 Grand构造 Parent构造 Child构造 Child析构 Parent析构 Grand析构 */构造顺序基类 → 成员对象 → 派生类构造函数体析构顺序完全相反二、基类没有无参构造的情况class Base { private: int b; public: Base(int val) : b(val) {} // 没有无参构造 }; class Derived : public Base { public: // 错误基类没有无参构造 // Derived() { } // 编译错误 // 正确在初始化列表中显式调用基类构造 Derived(int val) : Base(val) { } // 委托给其他构造函数 Derived() : Derived(0) { } };第五部分派生类的拷贝构造函数与赋值运算符一、拷贝构造函数class Base { protected: int b; public: Base(int val 0) : b(val) {} Base(const Base other) : b(other.b) { cout Base拷贝构造 endl; } }; class Derived : public Base { private: int d; public: Derived(int bv 0, int dv 0) : Base(bv), d(dv) {} // 派生类拷贝构造函数 Derived(const Derived other) : Base(other), // 调用基类拷贝构造 d(other.d) { // 拷贝派生类成员 cout Derived拷贝构造 endl; } void show() const { cout b b , d d endl; } }; int main() { Derived d1(10, 20); Derived d2(d1); // 调用拷贝构造 d2.show(); // b10, d20 return 0; }二、拷贝赋值运算符class Base { protected: int b; public: Base(int val 0) : b(val) {} Base operator(const Base other) { if (this ! other) { b other.b; cout Base赋值运算符 endl; } return *this; } }; class Derived : public Base { private: int d; public: Derived(int bv 0, int dv 0) : Base(bv), d(dv) {} // 派生类赋值运算符 Derived operator(const Derived other) { if (this ! other) { Base::operator(other); // 调用基类赋值运算符 d other.d; // 赋值派生类成员 cout Derived赋值运算符 endl; } return *this; } void show() const { cout b b , d d endl; } }; int main() { Derived d1(10, 20); Derived d2; d2 d1; // 调用赋值运算符 d2.show(); // b10, d20 return 0; }第六部分公有继承与私有继承的区别一、访问权限变化class Base { private: int a 1; protected: int b 2; public: int c 3; }; // 公有继承基类成员保持原有访问权限 class PublicDerived : public Base { // a: 不可访问 // b: protected // c: public }; // 私有继承基类成员全部变为 private class PrivateDerived : private Base { // a: 不可访问 // b: private // c: private }; int main() { PublicDerived pub; // pub.b; // 错误protected 不可访问 pub.c; // 正确public 可访问 PrivateDerived pri; // pri.c; // 错误私有继承后变为 private return 0; }二、使用场景继承方式语义使用场景publicis-a 关系绝大多数情况protected少见实现复用privateimplemented-in-terms-of实现继承不表达接口// 公有继承表达 is-a 关系 class Dog : public Animal { }; // Dog 是一种 Animal // 私有继承实现复用不表达接口 class Timer : private Clock { // Timer 使用 Clock 的功能但不是一种 Clock };第七部分继承与静态成员静态成员在整个继承体系中只有一份所有派生类共享。class Base { public: static int count; Base() { count; } ~Base() { count--; } }; int Base::count 0; class Derived : public Base { }; int main() { cout Base::count endl; // 0 Base b1, b2; cout Base::count endl; // 2 Derived d1, d2; cout Base::count endl; // 4所有对象共享 cout Derived::count endl; // 4通过派生类访问 return 0; }第八部分继承与友元友元关系不能继承。基类的友元不会自动成为派生类的友元。class Base { private: int secret 10; friend void friendOfBase(Base b); }; class Derived : public Base { private: int mySecret 20; }; void friendOfBase(Base b) { cout b.secret endl; // ✅ 可以访问 Base 的私有成员 } void test() { Derived d; // friendOfBase(d); // ✅ 可以传入派生类对象访问 Base 部分 // 但无法访问 d.mySecret } int main() { Derived d; // cout d.secret; // 错误secret 是 Base 的私有成员 return 0; }第九部分多重继承一、基本语法class Father { protected: int money 1000; public: void drive() { cout Father driving endl; } }; class Mother { protected: int money 2000; public: void cook() { cout Mother cooking endl; } }; class Child : public Father, public Mother { public: void show() { // cout money; // 二义性错误不知道是 Father::money 还是 Mother::money cout Father::money endl; // 1000 cout Mother::money endl; // 2000 } }; int main() { Child c; c.drive(); // Father 的成员 c.cook(); // Mother 的成员 c.show(); return 0; }二、菱形继承问题class Father { protected: int money 1000; public: void drive() { cout Father driving endl; } }; class Mother { protected: int money 2000; public: void cook() { cout Mother cooking endl; } }; class Child : public Father, public Mother { public: void show() { // cout money; // 二义性错误不知道是 Father::money 还是 Mother::money cout Father::money endl; // 1000 cout Mother::money endl; // 2000 } }; int main() { Child c; c.drive(); // Father 的成员 c.cook(); // Mother 的成员 c.show(); return 0; }三、虚继承解决菱形继承// 虚继承共享同一份基类子对象 class Grand { protected: int value 10; }; class Parent1 : virtual public Grand { }; class Parent2 : virtual public Grand { }; class Child : public Parent1, public Parent2 { public: void show() { cout value endl; // ✅ 只有一个 Grand无二义性 } }; int main() { Child c; c.show(); // 10 return 0; }四、虚继承的内存布局class Grand { int g; }; class Parent1 : virtual public Grand { int p1; }; class Parent2 : virtual public Grand { int p2; }; class Child : public Parent1, public Parent2 { int c; }; // 虚继承内存布局简化 // [Parent1部分][Parent2部分][Grand部分][Child部分] // Parent1 中有指向 Grand 的虚基类指针 // Parent2 中也有指向同一份 Grand 的虚基类指针第十部分完整示例#include iostream #include string using namespace std; class Person { private: int id; string name; protected: void setId(int i) { id i; } void setName(string n) { name n; } public: Person(int i 0, string n ) : id(i), name(n) { cout Person构造: name endl; } Person(const Person other) : id(other.id), name(other.name) { cout Person拷贝构造: name endl; } Person operator(const Person other) { if (this ! other) { id other.id; name other.name; cout Person赋值运算符 endl; } return *this; } virtual void show() const { cout Person: name ( id ) endl; } virtual ~Person() { cout Person析构: name endl; } }; class Student : virtual public Person { private: float score; public: Student(int i 0, string n , float s 0) : Person(i, n), score(s) { cout Student构造: score score endl; } Student(const Student other) : Person(other), score(other.score) { cout Student拷贝构造 endl; } Student operator(const Student other) { if (this ! other) { Person::operator(other); score other.score; cout Student赋值运算符 endl; } return *this; } void show() const override { Person::show(); cout Score: score endl; } ~Student() { cout Student析构 endl; } }; class Teacher : virtual public Person { private: string title; public: Teacher(int i 0, string n , string t ) : Person(i, n), title(t) { cout Teacher构造: title title endl; } void show() const override { Person::show(); cout Title: title endl; } ~Teacher() { cout Teacher析构 endl; } }; // 多重继承 虚继承 class TeachingAssistant : public Student, public Teacher { private: int workload; public: TeachingAssistant(int i, string n, float s, string t, int w) : Person(i, n), Student(i, n, s), Teacher(i, n, t), workload(w) { cout TA构造: workload workload endl; } void show() const override { Person::show(); cout Score: score endl; cout Title: title endl; cout Workload: workload h endl; } ~TeachingAssistant() { cout TA析构 endl; } }; int main() { cout 创建 TA endl; TeachingAssistant ta(1001, 张三, 95.5, 助教, 20); cout \n 调用 show endl; ta.show(); cout \n 拷贝构造 endl; TeachingAssistant ta2 ta; cout \n 赋值运算 endl; TeachingAssistant ta3; ta3 ta; cout \n 多态调用 endl; Person* p ta; p-show(); cout \n 对象销毁 endl; return 0; }总结一、继承关系核心要点特性说明存储布局基类子对象 派生类成员构造顺序基类 → 成员对象 → 派生类构造函数体析构顺序完全相反同名隐藏派生类同名成员隐藏基类所有重载赋值兼容派生类可赋值给基类切片公有继承is-a 关系最常用私有继承实现继承不表达接口虚继承解决菱形继承问题二、三/五法则扩展class Derived : public Base { public: // 构造函数 Derived(...) : Base(...) { } // 析构函数 ~Derived() { } // 拷贝构造 Derived(const Derived other) : Base(other) { } // 拷贝赋值 Derived operator(const Derived other) { if (this ! other) { Base::operator(other); // 赋值派生类成员 } return *this; } // 移动构造 Derived(Derived other) : Base(move(other)) { } // 移动赋值 Derived operator(Derived other) { if (this ! other) { Base::operator(move(other)); // 移动派生类成员 } return *this; } };三、快速参考场景推荐做法表达 is-a 关系公有继承实现复用私有继承 或 组合菱形继承虚继承基类无无参构造初始化列表显式调用避免切片传引用或指针多态基类析构函数设为 virtual继承是 C 面向对象编程的核心理解其底层机制对于写出正确、高效的代码至关重要。从存储布局到构造析构顺序从赋值兼容到多重继承每个知识点都值得深入理解。学习建议理解内存布局知道对象在内存中如何组织掌握构造/析构顺序避免资源管理错误谨慎使用多重继承优先考虑组合善用虚继承解决菱形继承问题