C++基础(十八):继承(重点)
发布日期:2025-06-20 11:53:15
浏览次数:10
分类:精选文章
本文共 4307 字,大约阅读时间需要 14 分钟。
C++继承机制详解
一、继承的概念及定义
1.1 继承的概念
继承是面向对象编程中实现代码复用的重要机制。它允许在保持基类功能的基础上,通过派生类扩展功能。继承体现了从简单到复杂的层次结构,帮助开发者更好地反映现实世界的事物层次。
示例:
class Person {public: void Print() { cout << "name:" << _name << endl; cout << "age:" << _age << endl; }protected: string _name = "peter"; int _age = 18;};class Student : public Person {protected: int _stuid; // 学号(新增的成员变量)};class Teacher : public Person {protected: int _jobid; // 工号(新增的成员变量)};int main() { Student s; Teacher t; s.Print(); t.Print(); return 0;} 继承带来的作用:
- 派生类可以拥有基类的成员变量和成员函数。
- 派生类可以定义自己的成员变量和函数。
1.2 继承定义
1.2.1 定义格式
基类和派生类的关系定义如下:
class Person { /*基类定义*/ };class Student : public Person { /*派生类定义*/ }; public:默认的继承方式,即派生类可以访问基类的所有成员。
1.2.2 继承关系与访问限定符
在C++中,继承时可以指定访问级别:
class Derived : private Base { }; // 派生类不能直接访问基类的private成员class Derived : protected Base { }; // 派生类可以访问基类的protected成员class Derived : public Base { }; // 默认继承方式,派生类可以访问基类的所有成员 访问级别的含义:
private:派生类无法访问基类的private成员。protected:派生类可以访问基类的protected成员,但无法访问基类的private成员。public:派生类可以访问基类的所有成员。
1.2.3 继承后的成员访问方式
基类成员在派生类中的访问方式取决于继承方式:
public:派生类可以直接访问基类的成员。protected:派生类可以通过基类的protected成员访问。private:派生类无法访问基类的private成员。
二、基类与派生类对象的赋值规则
2.1 子类可以赋值给父类
- 派生类对象可以赋值给基类对象、基类指针或基类引用。
- 这种赋值操作叫做“切割”或“截断”。
示例:
class Person {protected: string _name; string _sex; int _age;};class Student : public Person {public: int _No; // 学号};void Test() { Person p; Student s; // 派生类对象赋值给基类对象 Person p = s; Person* ptr = &s; Person& rp = s; // 基类指针或引用可以安全地指向派生类对象 ptr = &s; Student* ps = static_cast (ptr); ps->_No = 10; ptr = &p; Student* ps2 = static_cast (ptr); // 可能会导致越界访问 ps2->_No = 10;} 2.2 父类不能赋值给子类
- 基类对象不能直接赋值给派生类对象。
示例:
// 这段代码会报错Student s = p; // 错误,父类对象不能赋值给子类对象
2.3 父类赋值给子类的特殊情况
- 基类的指针或引用可以通过强制类型转换赋值给派生类的指针或引用,但前提是基类指针指向派生类对象。
- 使用
dynamic_cast来安全地进行类型转换。
示例:
class Teacher : public Person {public: int _jobid; // 工号};void Assign() { Person* basePtr = new Person(); Teacher* teacherPtr = new Teacher(); // 安全地将基类指针赋值给派生类指针 teacherPtr = dynamic_cast (basePtr); teacherPtr->_jobid = 123; // 不安全的转换示例 basePtr = new Person(); teacherPtr = static_cast (basePtr); // 可能导致越界访问} 三、继承中的作用域
3.1 隐藏的概念
在继承体系中,基类和派生类具有独立的作用域。
- 如果派生类和基类中存在同名成员(变量或函数),派生类的成员会屏蔽基类的成员。
- 这种现象称为“隐藏”,尤其是在同名成员函数时。
3.2 如何解决隐藏问题
- 在派生类的成员函数中,使用
Base::member来直接访问基类的成员。 - 避免在派生类和基类中定义相同的成员变量或函数。
示例:
class A {public: void fun() { cout << "func()" << endl; }};class B : public A {public: void fun(int i) { A::fun(); // 访问基类的成员 cout << "func(int i) - " << i << endl; }}; 3.3 注意事项
- 避免在继承体系中定义同名的成员变量或函数。
- 在派生类中使用
using Base::Base;来显式地声明基类成员。
四、继承的实际应用
4.1 实例化继承
通过继承,可以将基类的功能实例化为派生类,同时扩展功能。
示例:
class Animal {public: void Eat() { cout << "动物在吃..." << endl; }};class Dog : public Animal {public: void Bark() { cout << "狗在叫..." << endl; }};int main() { Animal* animal = new Animal(); Dog* dog = new Dog(); animal->Eat(); dog->Eat(); // 调用派生类的Eat函数 dog->Bark(); delete animal; delete dog;} 4.2 继承与多态
在支持多态的语言中,继承可以实现运行时绑定。
- 使用
dynamic_cast进行安全的类型转换。 - 基类方法可以有不同的实现方式。
示例:
class Shape {public: virtual void Draw() = 0;};class Circle : public Shape {public: void Draw() { cout << "画一个圆..." << endl; }};class Triangle : public Shape {public: void Draw() { cout << "画一个三角形..." << endl; }};void DrawShape(Shape* shape) { if (dynamic_cast (shape)) { shape->Draw(); cout << "是圆" << endl; } else if (dynamic_cast (shape)) { shape->Draw(); cout << "是三角形" << endl; }} 五、继承的常见问题
5.1 如何避免成员的隐藏
- 避免在派生类和基类中重复定义同名的成员。
- 使用
using语句显式地声明基类成员。
示例:
class Person {public: void Print() { cout << "name:" << _name << endl; cout << "age:" << _age << endl; }};class Student : public Person {public: using Person::Print; // 显式声明使用基类的Print函数 void NewPrint() { cout << "学号:" << _No << endl; Print(); // 调用基类的Print函数 }}; 5.2 如何处理多个继承层次
- 使用
struct关键字时,默认使用public继承。 - 在实际开发中,建议显式声明继承方式。
通过以上内容,我们可以清晰地理解C++继承的核心概念及其应用场景。掌握了继承的规则和注意事项后,可以在实际开发中灵活运用这一强大的工具。
发表评论
最新留言
很好
[***.229.124.182]2026年06月13日 14时29分53秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP如何获取当前页面的最后修改时间
2023-03-01
PHP如何读取json数据
2023-03-01
PHP字符串
2023-03-01
PHP字符串递增
2023-03-01
php学习之基础语法
2023-03-01
RabbitMQ集群 - 仲裁队列、Raft协议(最详细的选举流程)
2023-03-01
PHP学习总结(11)——PHP入门篇之WAMPServer多站点配置
2023-03-01
PHP学习总结(12)——PHP入门篇之变量
2023-03-01
PHP学习总结(13)——PHP入门篇之常量
2023-03-01
PHP学习总结(14)——PHP入门篇之常用运算符
2023-03-01
PHP学习总结(1)——PHP入门篇之PHP可以做什么?
2023-03-01
PHP学习总结(2)——PHP入门篇之PHP代码标识
2023-03-01
PHP学习总结(3)——PHP入门篇之PHP的echo语句
2023-03-01
PHP学习总结(4)——PHP入门篇之PHP计算表达式
2023-03-01
PHP学习总结(5)——PHP入门篇之PHP字符串
2023-03-01
PHP学习总结(6)——PHP入门篇之PHP语句结束符
2023-03-01
PHP学习总结(7)——PHP入门篇之PHP注释
2023-03-01
rabbitmq重启失败
2023-03-01
PHP学习总结(9)——PHP入门篇之WAMPServer服务控制面板介绍
2023-03-01
php学习笔记---php调试和开发工具整理
2023-03-01