跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 继承中的同名成员隐藏规则详解

综述由AI生成C++ 继承机制允许派生类复用基类特性并扩展功能。探讨了继承的定义格式、访问控制方式及基派生类间的转换规则。重点解析了作用域内的同名成员隐藏现象,区分了重载与隐藏的区别,并详细说明了派生类默认成员函数(构造、析构、赋值、拷贝)的调用顺序与实现细节,帮助开发者避免常见的命名冲突与资源管理错误。

灰度发布发布于 2026/3/28更新于 2026/6/917 浏览
C++ 继承中的同名成员隐藏规则详解

C++ 继承机制与同名成员隐藏

继承(inheritance)是面向对象编程中代码复用的核心手段。它允许我们在保持基类特性的基础上扩展功能,生成新的派生类。这不仅体现了程序的层次结构,也反映了从简单到复杂的认知过程。

一、什么是继承?

设计两个类 Student 和 Teacher 时,如果它们都有姓名、地址、电话等公共属性,直接定义在各自类中会导致大量冗余。通过引入一个 Person 基类,将公共成员提取出来,利用继承处理,就能避免重复定义。

class Person {
public:
    void identity() {
        cout << "void identity()" << _name << endl;
    }
protected:
    string _name = "张三";
    int _age = 18;
    string _address;
    string _tel;
};

class Student : public Person {
public:
    void study() {
        cout << "void study()" << endl;
    }
protected:
    int _stuid;
};

class Teacher : public Person {
public:
    void teaching() {
        cout << "void teaching()" << endl;
    }
protected:
    string _title;
};

int main() {
    Student s;
    Teacher t;
    s.identity();
    t.identity();
    return 0;
}

二、继承的定义

定义的格式

Person 是基类(父类),Student 是派生类(子类)。继承方式决定了基类成员在派生类中的访问权限。

继承方式主要有三种:public、protected、private。规则可以简单理解为取两者中更严格的访问级别(public > protected > private)。

  • 使用关键字 class 时,默认继承方式是 private。
  • 使用关键字 struct 时,默认继承方式是 public。
  • 实际开发中通常使用 public 继承,因为 protected/private 继承会限制派生类外部对成员的访问,降低扩展性和维护性。

继承类模板

继承不仅限于普通类,也可以继承类模板。例如用继承实现 stack 类,而不是仅靠适配器组合。

namespace say_fall {
    template<class T>
    class stack : public std::vector<T> {
    public:
        void push(const T& x) {
            // 基类是类模板时,需要指定作用域,否则编译报错
            // 因为 stack<int> 实例化时,vector<int> 的成员函数可能未实例化
            vector<T>::push_back(x);
        }
        void pop() {
            vector<T>::pop_back();
        }
        const T& top() {
            return vector<T>::back();
        }
        bool empty() {
            return vector<T>::empty();
        }
    };
}

int main() {
    say_fall::stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);
    while (!st.empty()) {
        cout << st.top() << " ";
        st.pop();
    }
    return 0;
}

这里用继承实现了栈,注意调用基类成员时需要显式指定作用域,这是因为模板按需实例化的特性。

三、基类和派生类之间的转换

继承关系类似于父子间的财产关系,有严格的转换规则:

  1. 向上转换:public 继承的派生类对象可以赋值给基类的指针或引用。这被称为'切片'(Slicing),即只保留派生类中属于基类的部分。
  2. 向下转换:基类对象不能直接赋值给派生类对象。基类指针/引用可以通过强制类型转换指向派生类对象,但必须确保基类指针确实指向了派生类对象,否则不安全。若基类是多态类型,建议使用 RTTI 的 dynamic_cast 进行安全识别。
class Person {
protected:
    string _name;
    string _sex;
    int _age;
};

class Student : public Person {
public:
    int _No;
};

int main() {
    Student sobj;
    // 1. 派生类对象可以赋值给基类的指针/引用
    Person* pp = &sobj;
    Person& rp = sobj;
    // 派生类对象赋值给基类对象是通过调用基类的拷贝构造完成的
    Person pobj = sobj;
    
    // 2. 基类对象不能赋值给派生类对象,编译报错
    // sobj = pobj; // 错误:没有匹配的运算符
    return 0;
}

四、继承的作用域

隐藏规则与重载比较

在继承体系中,基类和派生类拥有独立的作用域。当派生类和基类中存在同名成员时,派生类成员会屏蔽基类对同名成员的直接访问,这种现象称为隐藏。

  • 重载:发生在同一作用域下,参数不同的同名函数。
  • 隐藏:发生在不同作用域(基类与派生类),只要函数名相同即构成隐藏,无论参数是否一致。

如果在派生类成员函数中需要访问基类被隐藏的同名成员,可以使用 基类::成员名 显式访问。

class Person {
protected:
    string _name = "小李子";
    int _num = 111;
};

class Student : public Person {
public:
    void Print() {
        cout << "姓名:" << _name << endl;
        // 显式访问基类成员
        cout << "身份证号:" << Person::_num << endl;
        cout << "学号:" << _num << endl;
    }
protected:
    int _num = 999;
};

int main() {
    Student s1;
    s1.Print();
    return 0;
}

相关示例分析

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

class B : public A {
public:
    void fun(int i) { cout << "func(int i)" << i << endl; }
};

int main() {
    B b;
    b.fun(10); // 调用 B::fun(int)
    b.fun();   // 编译错误:B 中没有无参 fun,A 中的 fun 被隐藏
    return 0;
}

在这个例子中,A 和 B 的 fun 不构成重载,而是隐藏。因为它们在两个不同的作用域中。调用 b.fun() 时找不到匹配项,导致编译报错。

五、派生类默认成员函数

即使不手动实现,编译器也会为类生成默认成员函数。在继承关系中,这些函数的生成和调用遵循特定规则。

  1. 构造函数:派生类构造函数必须调用基类构造函数初始化基类部分。若基类无默认构造函数,必须在初始化列表中显式调用。
  2. 拷贝构造函数:派生类拷贝构造需调用基类拷贝构造完成基类部分的复制。
  3. 赋值运算符:派生类 operator= 会隐藏基类的 operator=。如需调用基类版本,需指定作用域 Base::operator=。
  4. 析构函数:派生类析构完成后会自动调用基类析构。顺序是先清理派生类成员,再清理基类成员。
  5. 多态与虚析构:在多态场景下,基类析构函数建议声明为 virtual。若非虚函数,派生类析构函数会与基类析构函数构成隐藏关系,可能导致资源泄漏。
class Person {
public:
    Person(const char* name = "peter") : _name(name) {
        cout << "Person()" << endl;
    }
    Person(const Person& p) : _name(p._name) {
        cout << "Person(const Person& p)" << endl;
    }
    Person& operator=(const Person& p) {
        cout << "Person operator=(const Person& p)" << endl;
        if (this != &p) _name = p._name;
        return *this;
    }
    ~Person() {
        cout << "~Person()" << endl;
    }
protected:
    string _name;
};

class Student : public Person {
public:
    Student(const char* name, int num) : Person(name), _num(num) {
        cout << "Student()" << endl;
    }
    Student(const Student& s) : Person(s), _num(s._num) {
        cout << "Student(const Student& s)" << endl;
    }
    Student& operator=(const Student& s) {
        cout << "Student& operator= (const Student& s)" << endl;
        if (this != &s) {
            // 显式调用基类赋值,防止递归调用自己的 operator=
            Person::operator=(s);
            _num = s._num;
        }
        return *this;
    }
    ~Student() {
        cout << "~Student()" << endl;
    }
protected:
    int _num;
};

int main() {
    Student s1("jack", 18);
    Student s2(s1);
    Student s3("rose", 17);
    s1 = s3;
    return 0;
}

注意赋值运算符的重载逻辑,如果不显式调用基类版本,可能会触发无限递归。析构顺序同样重要,确保资源按正确顺序释放。

目录

  1. C++ 继承机制与同名成员隐藏
  2. 一、什么是继承?
  3. 二、继承的定义
  4. 定义的格式
  5. 继承类模板
  6. 三、基类和派生类之间的转换
  7. 四、继承的作用域
  8. 隐藏规则与重载比较
  9. 相关示例分析
  10. 五、派生类默认成员函数
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Linux 内核设计中的核心思想与架构原则
  • .NET 集成 GoView 低代码可视化大屏实战指南
  • 开源 LLaVA-o1:基于自主多阶段推理的视觉语言模型解析
  • 零基础转行 Python 核心知识体系与学习路径
  • Python IDLE 使用教程:掌握 Python 自带集成开发环境
  • Qwen-Image-2512:消费级 GPU 上的高效 AI 绘画方案
  • Linux 进程信号的捕捉处理
  • 无水印保存豆包 AI 视频及图片的方法
  • Neo4j 图数据库从搭建到项目使用详解
  • Whisper Large v3 多语言语音识别 Web 服务部署实战
  • Python 爬虫入门指南:原理与基础实战
  • 多模态基础大模型技术白皮书解读与核心挑战分析
  • eBay API 授权码无效或过期错误排查指南
  • 分治算法实战:归并排序与数组逆序对详解
  • Kubernetes 集群从零部署图文教程
  • AI 大模型在制造业中的应用类型与核心能力
  • 开源鸿蒙终端工具 Termony 编译 -WSL 版
  • OpenClaw 为何爆火?AI Agent 从概念走向执行的破圈真相
  • Stable Diffusion WebUI 核心文件夹结构与模型实战指南
  • Paperzz 论文降重与 AIGC 检测功能分析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online