C++ 面向对象编程:继承与派生详解
在 C++ 面向对象编程中,继承 (Inheritance) 和 派生 (Derivation) 是两个核心概念,它们让我们能够实现代码复用、提升程序的扩展性。本文将结合示例代码和讲解图片,带你深入理解继承与派生的机制和使用方法。
1. 继承与派生的基本概念
-
继承:保持已有类的特性而构造新类的过程。
-
派生:在已有类的基础上新增自己的特性而产生新类的过程。
在继承体系中:
-
被继承的类称为 基类 (Base Class 或 父类)。
-
派生出的类称为 派生类 (Derived Class 或 子类)。
继承和派生的目的:
-
继承的目的:实现代码重用,提高扩展性。
-
派生的目的:当原有程序无法解决新问题时,可以在原有类的基础上扩展功能。
2. 继承方式:public / protected / private
2.1 公有继承 (public)
特点:
-
基类的 public 成员在子类中保持 public。
-
基类的 protected 成员在子类中保持 protected。
-
基类的 private 成员在子类中不可直接访问。
类外访问:
-
只能通过子类对象访问基类的 public 成员。
代码示例:
#include <iostream>
using namespace std;
#if 0
class A
{
public:
void fun_A_public()
{
cout << "fun_A_public" << endl;
}
protected:
void fun_A_protected()
{
cout << "fun_A_protected" << endl;
}
private:
void fun_A_private()
{
cout << "fun_A_private" << endl;
}
};
// 继承方式:public、protected、private
// 1、继承方式只影响父类的成员在子类中是否需要改变访问属性,
// 也就是父类中的成员拷贝到子类中后,这些成员在子类中的其存在的访问权限
// 2、子类中是否能够访问基类中的成员,与继承方式是没有关系的。
// 子类中是否能访问基类中的成员,只与原基类中成员访问权限有关,
// 父类中的private成员子类无法访问,public、protected成员是可以直接访问。
class B : public A
{
public:
void fun_B_public()
{
cout << "fun_B_public" << endl;
// 子类中可以直接调用或访问父类中的public、protected成员,
// 不需要使用类对象访问,因为继承本质就是我子类复用了基类的代码。
fun_A_public();
fun_B_private();
// 子类中无法访问父类中的private成员
// fun_A_private();
fun_A_protected();
}
protected:
void fun_B_protected()
{
cout << "fun_B_protected" << endl;
fun_A_protected();
}
private:
void fun_B_private()
{
cout << "fun_B_private" << endl;
}
};
int main(int argc, char *argv[])
{
B b;
// 1、父类中的public成员,在使用public方式继承时,
// 其可以通过子类对象,在类的外部直接访问。
// 2、无论是什么继承方式,父类中的protected、private成员,在类外部都无法访问。
b.fun_A_public();
b.fun_B_public();
2.2 保护继承 (protected)
特点:
-
基类的 public 成员在子类中变为 protected。
-
基类的 protected 成员依然是 protected。
-
基类的 private 成员依然不可访问。
类外访问:
-
子类对象无法直接访问从基类继承的 public 成员,只能在子类内部访问。
2.3 私有继承 (private)
特点:
-
基类的 public 和 protected 成员在子类中都变为 private。
-
基类的 private 成员依然不可访问。
类外访问:
-
子类对象无法直接访问继承的成员。
3. 构造与析构顺序
在 C++ 中,当类之间存在组合或继承关系时,构造和析构的调用顺序尤为重要。
3.1 组合关系
#include <iostream>
using namespace std;
class A
{
public:
A();//无参构造
A(int a, int b);//带参构造
~A();
private:
int m_AA;
int m_AB;
};
class C
{
public:
C(int a);
~C();
private:
int m_C;
};
//当创建一个“容器”类的对象时(这里是B),会首先构造它的成员变量,然后才执行它自身的构造函数体。成员变量的构造顺序严格按照它们在类中声明的顺序,与它们在构造函数初始化列表中的顺序无关。
class B
{
public:
B(int b, int c);
~B();
private:
C ccc;
A aaa; // 类组合关系
int m_B;
};
A::A()
{
cout << "A construct" << endl;
}
A::A(int a, int b) : m_AA(a), m_AB(b)
{
cout << "A construct: " << m_AA << " : " << m_AB << endl;
}
A::~A()
{
cout << "A descstruct: " << m_AA << " : " << m_AB << endl;
}
// 类组合时,当前类负责初始化构造组合类
// 原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。
// 如果A类是无参构造,那么可以不用管,系统会自动调用其无参构造
// 如果我们需要使用A类的带参构造,那么B类必须负责A类的构造
B::B(int b, int c) : ccc(b), aaa(b, c), m_B(c)
{
// 不允许访问组合类中的私有成员
//aaa.m_AA = 11112;
cout << "B construct: " << m_B << endl;
}
B::~B()
{
cout << "B descstruct: " << m_B << endl;
}
C::C(int a) : m_C(a)
{
cout << "C construct: " << m_C << endl;
}
C::~C()
{
cout << "C descstruct: " << m_C << endl;
}
int main(int argc, char *argv[])
{
// 在拥有组合关系时,当前B类中有一个A类对象的成员变量
// 其构造顺序:
// 1、先构造B的成员变量,但是由于成员变量中拥有A类对象
// 2、所以调转至A类进行构造,先构造其成员变量
// 3、在执行A类的构造函数
// 4、返回B类,如果有未构造的其它成员变量,继续构造
// 5、最后在执行B类构造函数
B b(123, 456);
return 0;
}
执行顺序:
-
先构造 B 的成员变量(
C、A)。 -
然后执行 B 的构造函数。
-
析构时顺序相反:先析构 B 自身,再析构其成员。
3.2 继承关系
class A {
public:
A(double val) { cout << "A construct with value: " << val << endl; }
~A() { cout << "A destruct" << endl; }
};
class B : public A {
public:
B(double n) : A(n) { cout << "B construct" << endl; }
~B() { cout << "B destruct" << endl; }
};
int main() {
B myB(99.5);
return 0;
}
执行顺序:
-
先调用基类 A 的构造函数。
-
再执行派生类 B 的构造函数。
-
析构顺序相反:先析构 B,再析构 A。
4. 内部访问与外部访问
派生类可以访问基类的 public 和 protected 成员,但不能访问 private 成员。下面是派生类内部函数 show_all_internal_access 的示例:
void show_all_internal_access() {
cout << "--- Inherited from A ---" << endl;
fun_A_public(); // ✅ 可访问
fun_A_protected(); // ✅ 可访问
// fun_A_private(); // ❌ 不可访问
cout << "--- B's Own Members ---" << endl;
fun_B_public(); // ✅ 可访问
fun_B_protected(); // ✅ 可访问
fun_B_private(); // ✅ 可访问
}
5. 总结
-
继承和派生是 C++ 面向对象编程的基石。
-
public / protected / private 继承方式决定了基类成员在子类中的可见性和访问权限。
-
构造与析构顺序遵循 先基类 → 后子类,析构顺序相反 的原则。
-
子类内部能访问基类的
public和protected,但不能访问private。
通过理解这些规则,我们就能写出更清晰、更易维护的 C++ 面向对象代码。

3865

被折叠的 条评论
为什么被折叠?



