C++继承:面向对象的核心特性
·
🎯 一、什么是继承?
继承是面向对象编程中实现代码复用的重要手段。它允许我们在保持原有类特性的基础上进行扩展,增加新的成员变量和成员函数,从而产生新的类(称为派生类或子类)。
继承的优势:
- ✅ 减少代码冗余
- ✅ 提高代码复用性
- ✅ 体现类之间的层次关系
// 没有继承时的冗余代码
class Student {
string _name;
int _age;
void identity() { /* ... */ }
};
class Teacher {
string _name; // 重复
int _age; // 重复
void identity() { /* ... */ } // 重复
};
// 使用继承
class Person {
protected:
string _name;
int _age;
void identity() { /* ... */ }
};
class Student : public Person {
// 继承Person的所有成员
// 只需要添加学生特有的成员
};
class Teacher : public Person {
// 只需要添加老师特有的成员
};
🎯 二、继承的基本语法和访问权限
// 继承语法:class 派生类 : 继承方式 基类
class Student : public Person {
// 派生类特有的成员
int _stuid; // 学号
void study() { /* 学习 */ }
};
三种继承方式:
访问权限变化表:
| 基类成员/继承方式 | public继承 | protected继承 | private继承 |
|---|---|---|---|
| public成员 | public | protected | private |
| protected成员 | protected | protected | private |
| private成员 | 不可见 | 不可见 | 不可见 |
关键点:
- 基类private成员在派生类中不可见,但确实被继承了
- protected成员专门为继承设计,派生类可以访问
- 实际开发中,99%的情况使用public继承
🎯 三、派生类的构造函数和析构函数
构造和析构顺序:
class Person {
public:
Person(string name) : _name(name) {
cout << "Person构造" << endl;
}
~Person() {
cout << "Person析构" << endl;
}
protected:
string _name;
};
class Student : public Person {
public:
Student(string name, int id)
: Person(name), _stuid(id) { // 必须调用基类构造
cout << "Student构造" << endl;
}
~Student() {
cout << "Student析构" << endl;
// 自动调用基类析构
}
private:
int _stuid;
};
🎯 四、继承中的隐藏问题
当派生类中有与基类同名的成员时,派生类成员会隐藏基类成员:
class Person {
public:
void func() { cout << "Person::func" << endl; }
};
class Student : public Person {
public:
void func(int i) { // 隐藏基类的func()
cout << "Student::func" << endl;
}
};
int main() {
Student s;
s.func(10); // 正确:调用Student::func(int)
// s.func(); // 错误:基类func()被隐藏
s.Person::func(); // 正确:使用作用域运算符
}
🎯 五、切片(赋值兼容性)
重要规则: 派生类对象可以赋值给基类对象,但反过来不行。
class Person { /* ... */ };
class Student : public Person { /* ... */ };
int main() {
Student stu;
// ✅ 派生类 -> 基类(切片)
Person p1 = stu; // 对象赋值
Person* p2 = &stu; // 指针
Person& p3 = stu; // 引用
// ❌ 基类 -> 派生类(不允许)
// Student s = p1; // 编译错误
return 0;
}
🎯 六、多继承与菱形继承
多继承结构:
// 一个类有多个直接基类
class Assistant : public Student, public Teacher {
// 同时具有Student和Teacher的特性
};
菱形继承问题:
class Person { string _name; };
class Student : public Person { /* ... */ };
class Teacher : public Person { /* ... */ };
class Assistant : public Student, public Teacher { /* ... */ };
Assistant a;
// a._name = "张三"; // 错误:二义性,不知道用哪个_name
a.Student::_name = "张三"; // 需要指定
a.Teacher::_name = "李四";
// 问题:Assistant对象中有两份_name,浪费空间
解决方案:虚继承
class Person { string _name; };
class Student : virtual public Person { /* ... */ }; // 虚继承
class Teacher : virtual public Person { /* ... */ }; // 虚继承
class Assistant : public Student, public Teacher { /* ... */ };
Assistant a;
a._name = "张三"; // 正确:只有一份_name
🎯 七、继承 vs 组合
| 特性 | 继承(is-a) | 组合(has-a) |
|---|---|---|
| 关系 | "是一个"关系 | "有一个"关系 |
| 示例 | 学生是一个人 | 汽车有轮胎 |
| 耦合度 | 高 | 低 |
| 复用方式 | 白箱复用 | 黑箱复用 |
| 建议 | 需要多态时使用 | 优先使用 |
// 继承:is-a关系
class Car { /* 汽车通用功能 */ };
class BMW : public Car { /* 宝马特有功能 */ };
// 组合:has-a关系
class Tire { /* 轮胎 */ };
class Car {
Tire _tire1, _tire2, _tire3, _tire4; // 汽车有4个轮胎
};
📝 总结
继承是C++面向对象编程的核心特性,使用时需要注意:
- ✅ 优先使用public继承
- ✅ 注意构造和析构的顺序
- ✅ 小心同名成员的隐藏问题
- ✅ 理解切片机制
- ✅ 避免菱形继承,必要时使用虚继承
- ✅ 优先考虑组合,需要多态时才用继承
继承让代码更易维护和扩展,但不当使用也会导致问题。掌握好继承的规则和技巧,能让你的面向对象设计更加优雅。

更多推荐



所有评论(0)