1. 继承的基本概念
继承是面向对象编程的核心特性之一,允许我们基于已有类创建新类,实现代码重用和建立类之间的层次关系。
基本语法
class 派生类名 : 继承方式 基类名 {
// 派生类成员
};2. 继承方式
C++支持三种继承方式:
2.1 公有继承(public)
class Animal {
public:
void eat() { cout << "Eating..." << endl; }
protected:
int age;
private:
int id;
};
class Dog : public Animal { // 公有继承
public:
void bark() {
eat(); // 可以访问public成员
age = 5; // 可以访问protected成员
// id = 10; // 错误!不能访问private成员
}
};访问权限变化:
- 基类的 public → 派生类的 public
- 基类的 protected → 派生类的 protected
- 基类的 private → 派生类中不可访问
2.2 保护继承(protected)
class Dog : protected Animal {
// 基类的public和protected成员都变为protected
};2.3 私有继承(private)
class Dog : private Animal {
// 基类的public和protected成员都变为private
};3. 构造函数和析构函数
3.1 调用顺序
class Base {
public:
Base() { cout << "Base构造" << endl; }
~Base() { cout << "Base析构" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived构造" << endl; }
~Derived() { cout << "Derived析构" << endl; }
};
int main() {
Derived d;
// 输出顺序:
// Base构造
// Derived构造
// Derived析构
// Base析构
}3.2 向基类构造函数传递参数
class Person {
protected:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
};
class Student : public Person {
private:
string school;
public:
// 使用初始化列表调用基类构造函数
Student(string n, int a, string s)
: Person(n, a), school(s) {}
};4. 函数重写(Override)
4.1 普通函数重写
class Shape {
public:
void draw() {
cout << "Drawing shape" << endl;
}
};
class Circle : public Shape {
public:
void draw() { // 隐藏基类的draw函数
cout << "Drawing circle" << endl;
}
};4.2 虚函数和多态
class Shape {
public:
virtual void draw() { // 虚函数
cout << "Drawing shape" << endl;
}
virtual double area() = 0; // 纯虚函数
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
void draw() override { // C++11 override关键字
cout << "Drawing rectangle" << endl;
}
double area() override {
return width * height;
}
};5. 多重继承
C++支持一个类继承多个基类:
class Vehicle {
public:
void start() { cout << "Vehicle starting" << endl; }
};
class Flyable {
public:
void fly() { cout << "Flying" << endl; }
};
class FlyingCar : public Vehicle, public Flyable {
public:
void travel() {
start(); // 从Vehicle继承
fly(); // 从Flyable继承
}
};5.1 菱形继承问题
class Animal {
public:
int age;
};
class Mammal : public Animal {};
class Bird : public Animal {};
class Bat : public Mammal, public Bird {}; // 菱形继承
// 解决方案:虚继承
class Mammal : virtual public Animal {};
class Bird : virtual public Animal {};
class Bat : public Mammal, public Bird {}; // 现在只有一份Animal6. 完整示例:员工管理系统
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
// 基类
class Employee {
protected:
string name;
int id;
double baseSalary;
public:
Employee(string n, int i, double s)
: name(n), id(i), baseSalary(s) {}
virtual ~Employee() {} // 虚析构函数很重要!
// 虚函数,计算工资
virtual double calculateSalary() const {
return baseSalary;
}
virtual void displayInfo() const {
cout << "姓名: " << name
<< ", ID: " << id
<< ", 工资: " << calculateSalary() << endl;
}
};
// 派生类:经理
class Manager : public Employee {
private:
double bonus;
public:
Manager(string n, int i, double s, double b)
: Employee(n, i, s), bonus(b) {}
double calculateSalary() const override {
return baseSalary + bonus;
}
void displayInfo() const override {
cout << "经理 - ";
Employee::displayInfo(); // 调用基类版本
}
};
// 派生类:销售人员
class SalesPerson : public Employee {
private:
double commission;
double sales;
public:
SalesPerson(string n, int i, double s, double c, double sal)
: Employee(n, i, s), commission(c), sales(sal) {}
double calculateSalary() const override {
return baseSalary + (sales * commission);
}
void displayInfo() const override {
cout << "销售 - ";
Employee::displayInfo();
}
};
int main() {
vector<unique_ptr<Employee>> employees;
employees.push_back(make_unique<Manager>("张三", 1001, 8000, 3000));
employees.push_back(make_unique<SalesPerson>("李四", 1002, 5000, 0.1, 50000));
employees.push_back(make_unique<Employee>("王五", 1003, 6000));
cout << "员工信息:" << endl;
for (const auto& emp : employees) {
emp->displayInfo(); // 多态调用
}
return 0;
}7. 继承的最佳实践
7.1 设计原则
- 优先使用组合而非继承
- 使用public继承表示”is-a”关系
- 基类析构函数应该是虚函数或protected
- 不要继承非接口类(如STL容器)
7.2 注意事项
class Base {
public:
virtual ~Base() = default; // 虚析构函数
Base(const Base&) = default; // 拷贝构造
Base& operator=(const Base&) = default; // 赋值运算符
};
class Derived : public Base {
// 编译器会自动生成合适的版本
};继承是C++中强大但复杂的特性,正确使用可以提高代码的可维护性和复用性,但过度使用会导致代码难以理解和维护。