C++继承和派生

本文详细介绍了C++中的继承和派生概念,包括三种继承方式(public、protected、private)及其对成员访问权限的影响,名字遮蔽问题,以及基类成员函数和派生类成员函数的关系。还探讨了多继承、虚继承、虚基类的构造函数和对象内存模型,以及派生类与基类之间的构造函数和析构函数调用顺序。最后讨论了将派生类赋值给基类的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.C++继承和派生

继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数。

派生(Derive和继承是一个概念,只是站的角度不同。继承是儿子接收父亲的产业,派生是父亲把产业传承给儿子。

被继承的类称为父类或基类,继承的类称为子类或派生类。

2.C++三种继承方式

继承方式限定了基类成员在派生类中的访问权限,包括 public(公有的)、private(私有的)和 protected(受保护的)。此项是可选项,如果不写,默认为 private(成员变量和成员函数默认也是 private)。

类成员的访问权限由高到低依次为 public --> protected --> private,public 成员可以通过对象来访问,private 成员不能通过对象访问。
protected 成员和 private 成员类似,也不能通过对象访问。但是当存在继承关系时,protected 和 private 就不一样了:基类中的 protected 成员可以在派生类中使用,而基类中的 private 成员不能在派生类中使用。

1) public继承方式

  • 基类中所有 public 成员在派生类中为 public 属性;
  • 基类中所有 protected 成员在派生类中为 protected 属性;
  • 基类中所有 private 成员在派生类中不能使用。

2) protected继承方式

  • 基类中的所有 public 成员在派生类中为 protected 属性;
  • 基类中的所有 protected 成员在派生类中为 protected 属性;
  • 基类中的所有 private 成员在派生类中不能使用。

3) private继承方式

  • 基类中的所有 public 成员在派生类中均为 private 属性;
  • 基类中的所有 protected 成员在派生类中均为 private 属性;
  • 基类中的所有 private 成员在派生类中不能使用。

基类成员在派生类中的访问权限不得高于继承方式中指定的权限。

继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。

基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。

在派生类中访问基类 private 成员的唯一方法就是借助基类的非 private 成员函数,如果基类没有非 private 成员函数,那么该成员在派生类中将无法访问。

改变访问权限

使用 using 关键字可以改变基类成员在派生类中的访问权限,例如将 public 改为 private、将 protected 改为 public。

using 只能改变基类中 public 和 protected 成员的访问权限,不能改变 private 成员的访问权限,因为基类中 private 成员在派生类中是不可见的,根本不能使用,所以基类中的 private 成员在派生类中无论如何都不能访问。

#include<iostream>
using namespace std;
//基类People
class People {
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
void People::show() {
    cout << m_name << "的年龄是" << m_age << endl;
}
//派生类Student
class Student : public People {
public:
    void learning();
public:
    using People::m_name;  //将protected改为public
    using People::m_age;  //将protected改为public
    float m_score;
private:
    using People::show;  //将public改为private
};
void Student::learning() {
    cout << "我是" << m_name << ",今年" << m_age << "岁,这次考了" << m_score << "分!" << endl;
}
int main() {
    Student stu;
    stu.m_name = "小明";
    stu.m_age = 16;
    stu.m_score = 99.5f;
    stu.show();  //compile error
    stu.learning();
    return 0;
}

3.C++继承时的名字遮蔽问题

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。

#include<iostream>
using namespace std;
//基类People
class People{
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
void People::show(){
    cout<<"嗨,大家好,我叫"<<m_name<<",今年"<<m_age<<"岁"<<endl;
}
//派生类Student
class Student: public People{
public:
    Student(char *name, int age, float score);
publ
### C++继承派生的概念 继承派生是面向对象编程的核心机制之一,允许一个类(派生类)基于另一个类(基类)定义其属性行为。这种机制使得派生类不仅可以复用基类的成员,还可以扩展或修改其功能,从而实现代码的重用层次化设计[^1]。 继承体现了类型之间的“是一种”关系(is-a),例如“狗是一种动物”。派生类在继承基类成员的基础上,可以添加新的成员变量成员函数,以表达更具体的行为状态[^2]。 ### 使用方法 C++ 中的继承通过在类定义中使用冒号 `:` 指定基类,并可选择继承方式(`public`、`protected` 或 `private`)。最常见的是公有继承(`public`),它使得基类的公有成员在派生类中仍为公有,保护成员变为保护成员,而私有成员不可访问。 派生类构造函数需要显式调用基类构造函数以初始化继承的成员。如果未显式调用,编译器会尝试调用基类的默认构造函数。若基类没有默认构造函数,则会导致编译错误。 派生类可以访问基类的公有保护成员,但不能直接访问私有成员。此外,派生类可以重写基类的虚函数以实现多态行为。 ### 示例 以下是一个简单的继承派生示例,展示如何定义基类派生类,并调用其成员函数: ```cpp #include <iostream> using namespace std; // 基类 class Animal { public: virtual void speak() const { cout << "Animal speaks" << endl; } }; // 派生类 class Dog : public Animal { public: void speak() const override { cout << "Woof!" << endl; } }; int main() { Dog myDog; myDog.speak(); // 输出 "Woof!" return 0; } ``` 在这个例子中,`Dog` 类公有继承了 `Animal` 类,并重写了 `speak()` 函数以实现不同的行为。由于 `speak()` 是虚函数,因此可以通过基类指针或引用调用派生类的实现,实现多态性。 ### 构造函数与析构函数的调用顺序 派生类的构造函数必须负责调用基类的构造函数来初始化继承的成员。例如: ```cpp class Base { public: Base(int x) { cout << "Base constructor called with " << x << endl; } }; class Derived : public Base { public: Derived(int x, int y) : Base(x) { cout << "Derived constructor called with " << y << endl; } }; ``` 当创建 `Derived` 对象时,首先调用 `Base` 的构造函数,然后执行 `Derived` 的构造函数体。析构过程则相反,先析构派生类,再析构基类。 ### 静态成员的继承 静态成员函数静态变量在派生类中是共享的,它们属于类本身而不是对象。例如: ```cpp class Base { public: static void info() { cout << "Base static info" << endl; } }; class Derived : public Base {}; int main() { Derived::info(); // 调用 Base 的静态函数 return 0; } ``` 如果派生类定义了同名的静态函数,则会隐藏基类的版本,但可以通过作用域解析运算符访问: ```cpp class Derived : public Base { public: static void info() { cout << "Derived static info" << endl; } }; int main() { Derived::info(); // 输出 "Derived static info" Base::info(); // 输出 "Base static info" return 0; } ``` ### 内存布局 派生类的内存布局包括基类的成员派生类新增的成员。基类的成员位于派生类对象内存的低地址部分,新增成员位于高地址部分。无论继承多少层,静态成员函数变量在整个程序中只有一份副本,存放在静态存储区[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值