深入浅出C++继承机制:从入门到实战

目录

深入浅出C++继承机制:从入门到实战

一、继承的基本概念

二、继承的访问控制

三、继承中的特殊关系

1. 基类与派生类的转换

2. 继承中的作用域

3. 派生类的默认成员函数

四、多继承与菱形继承

1. 多继承模型

2. 菱形继承问题

3. 虚继承解决方案

五、继承与组合的选择

六、继承实战技巧

七、总结


深入浅出C++继承机制:从入门到实战

面向对象编程中,继承是最强大的特性之一,也是C++程序员必须掌握的核心概念。今天我们就来全面解析C++继承机制,从基础概念到高级应用,让你彻底搞懂继承!

一、继承的基本概念

继承是面向对象程序设计使代码可以复用的最重要手段。想象一下,学校里有老师和学生,他们都有姓名、年龄、地址等共同属性,但又有各自独特的属性(老师有职称,学生有学号)。如果分别定义两个类,就会出现大量重复代码。

class Person {
protected:
    string _name = "张三"; // 姓名
    int _age = 18;        // 年龄
    string _address;      // 地址
    string _tel;          // 电话
};

class Student : public Person {
protected:
    int _stuid; // 学号
};

class Teacher : public Person {
protected:
    string _title; // 职称
};

通过继承,我们可以把公共成员放到Person基类中,Student和Teacher都继承Person,这样就避免了重复定义,代码更加简洁优雅。

二、继承的访问控制

继承方式有三种:public、protected和private。它们决定了基类成员在派生类中的访问权限:

基类成员/继承方式public继承protected继承private继承
public成员publicprotectedprivate
protected成员protectedprotectedprivate
private成员不可见不可见不可见

几点重要说明:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的
  2. protected成员是专为继承设计的访问级别
  3. 实际开发中绝大多数情况使用public继承
class Base {
public:
    int publicVar;
protected:
    int protectedVar;
private:
    int privateVar;
};

class Derived : public Base {
    // publicVar仍然是public
    // protectedVar仍然是protected
    // privateVar不可见
};

三、继承中的特殊关系

1. 基类与派生类的转换

Student sobj;
// 派生类对象可以赋值给基类的指针/引用(切片)
Person* pp = &sobj;
Person& rp = sobj;

// 基类对象不能赋值给派生类对象(编译报错)
// sobj = pobj; 

2. 继承中的作用域

当基类和派生类有同名成员时,派生类成员会隐藏基类成员:

class Base {
public:
    void func() { cout << "Base::func()" << endl; }
};

class Derived : public Base {
public:
    void func() { cout << "Derived::func()" << endl; }
    // 如果要访问基类的func,需要使用Base::func()
};

3. 派生类的默认成员函数

派生类的构造/析构等特殊成员函数有一些特殊规则:

class Person {
public:
    Person(const char* name = "peter") : _name(name) {}
    // ...
};

class Student : public Person {
public:
    Student(const char* name, int num)
        : Person(name)  // 必须调用基类构造函数
        , _num(num) 
    {}
    // ...
};

四、多继承与菱形继承

1. 多继承模型

class Worker {
    // 工人特有属性和方法
};

class Student {
    // 学生特有属性和方法
};

class WorkingStudent : public Worker, public Student {
    // 既是工人又是学生
};

2. 菱形继承问题

菱形继承是多继承的一种特殊情况,会导致数据冗余和二义性:

class Person {
    string _name;
};

class Student : public Person {
    int _num;
};

class Teacher : public Person {
    int _id;
};

class Assistant : public Student, public Teacher {
    // 这里Person的成员会有两份!
};

3. 虚继承解决方案

使用虚继承可以解决菱形继承问题:

class Person {
    string _name;
};

class Student : virtual public Person {
    int _num;
};

class Teacher : virtual public Person {
    int _id;
};

class Assistant : public Student, public Teacher {
    // 现在_name只有一份了
};

五、继承与组合的选择

在设计类关系时,需要慎重考虑使用继承还是组合:

// 继承(is-a关系)
class BMW : public Car {
    void Drive() { cout << "好开-操控" << endl; }
};

// 组合(has-a关系)
class Stack {
    vector<int> _v;  // 使用组合而非继承
};

一般原则:

  • 如果确实是"is-a"关系,使用继承
  • 如果是"has-a"关系,使用组合
  • 当两者都适用时,优先考虑组合

六、继承实战技巧

  1. ​final关键字​​:C++11引入final关键字,可以禁止类被继承
class Base final {
    // 这个类不能被继承
};
  1. ​静态成员继承​​:基类的静态成员在整个继承体系中只有一份
class Base {
public:
    static int count;
};
int Base::count = 0;

class Derived : public Base {
    // 共享同一个count
};
  1. ​友元关系不继承​​:基类的友元不能访问派生类的私有成员

七、总结

继承是C++面向对象编程的核心特性,合理使用可以:

  • 提高代码复用性
  • 建立清晰的类层次结构
  • 实现多态(配合虚函数)

但也要注意:

  • 避免过度使用继承
  • 警惕菱形继承问题
  • 在继承和组合之间做出明智选择

掌握好继承机制,你的C++面向对象设计能力将更上一层楼!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值