C++ 继承
外观
C++继承[编辑 | 编辑源代码]
继承是C++面向对象编程中的核心概念之一,它允许一个类(称为派生类或子类)基于另一个类(称为基类或父类)来构建,从而复用代码并建立类之间的层次关系。继承体现了"is-a"关系,是代码重用和多态性的基础。
基本语法[编辑 | 编辑源代码]
C++中继承的基本语法如下:
class BaseClass {
// 基类成员
};
class DerivedClass : access-specifier BaseClass {
// 派生类成员
};
其中access-specifier可以是public、protected或private,决定了基类成员在派生类中的访问权限。
继承类型[编辑 | 编辑源代码]
C++支持三种继承方式:
1. 公有继承(public)[编辑 | 编辑源代码]
最常用的继承方式,保持基类成员的原有访问权限:
- 基类的public成员 → 派生类的public成员
- 基类的protected成员 → 派生类的protected成员
- 基类的private成员 → 不可访问
class Animal {
public:
void breathe() { cout << "Breathing..." << endl; }
protected:
int age;
};
class Dog : public Animal {
public:
void bark() {
breathe(); // 可以访问基类public方法
age = 2; // 可以访问基类protected成员
}
};
2. 保护继承(protected)[编辑 | 编辑源代码]
- 基类的public和protected成员 → 派生类的protected成员
- 基类的private成员 → 不可访问
3. 私有继承(private)[编辑 | 编辑源代码]
- 基类的public和protected成员 → 派生类的private成员
- 基类的private成员 → 不可访问
构造函数和析构函数顺序[编辑 | 编辑源代码]
当创建派生类对象时: 1. 先调用基类构造函数 2. 然后调用派生类构造函数 析构时顺序相反。
示例:
class Base {
public:
Base() { cout << "Base constructor" << endl; }
~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived constructor" << endl; }
~Derived() { cout << "Derived destructor" << endl; }
};
int main() {
Derived d;
return 0;
}
输出:
Base constructor Derived constructor Derived destructor Base destructor
函数重写与多态[编辑 | 编辑源代码]
派生类可以重写(override)基类的虚函数,实现运行时多态:
class Shape {
public:
virtual void draw() { cout << "Drawing a shape" << endl; }
virtual ~Shape() {} // 虚析构函数
};
class Circle : public Shape {
public:
void draw() override { cout << "Drawing a circle" << endl; }
};
int main() {
Shape* shape = new Circle();
shape->draw(); // 输出"Drawing a circle"
delete shape;
return 0;
}
多重继承[编辑 | 编辑源代码]
C++支持一个类继承多个基类(但需谨慎使用,可能引发"菱形问题"):
class A {
public:
void funcA() { cout << "Function A" << endl; }
};
class B {
public:
void funcB() { cout << "Function B" << endl; }
};
class C : public A, public B {
public:
void funcC() {
funcA();
funcB();
}
};
虚继承[编辑 | 编辑源代码]
解决多重继承中的菱形问题:
class A {
public:
int data;
};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
int main() {
D d;
d.data = 10; // 没有二义性
return 0;
}
实际应用案例[编辑 | 编辑源代码]
GUI框架中的继承 在图形用户界面开发中,继承被广泛使用:
class Widget {
protected:
int x, y;
public:
virtual void draw() = 0;
virtual void handleEvent(Event e) = 0;
};
class Button : public Widget {
string label;
public:
void draw() override { /* 绘制按钮 */ }
void handleEvent(Event e) override {
if (e.type == Event::Click) {
// 处理点击事件
}
}
};
class CheckBox : public Widget {
bool checked;
public:
void draw() override { /* 绘制复选框 */ }
void handleEvent(Event e) override {
if (e.type == Event::Click) {
checked = !checked;
}
}
};
继承与组合[编辑 | 编辑源代码]
虽然继承强大,但有时组合(has-a关系)比继承(is-a关系)更合适:
- 继承:当派生类确实是基类的特殊类型时使用
- 组合:当一个类需要另一个类的功能但不是其特殊类型时使用
最佳实践[编辑 | 编辑源代码]
1. 优先使用公有继承 2. 谨慎使用多重继承 3. 基类析构函数应声明为virtual 4. 考虑使用final禁止进一步派生 5. 遵循LSP(里氏替换原则):派生类应能完全替代基类
进阶主题[编辑 | 编辑源代码]
- 协变返回类型
- 使用using改变基类成员访问权限
- CRTP(奇异递归模板模式)
- 接口继承与实现继承
通过掌握继承,您可以构建更灵活、可维护的面向对象系统。记住,继承是手段而非目的,合理设计类层次结构比滥用继承更重要。