详细介绍:C++工程实战入门笔记12-继承、派生、保护、公开、私有

代码

#include<iostream>
  using namespace std;
  #include<string>
    //基类:父类
    class Base
    {
    public:
    Base() { cout <<
    "create base " << name<<endl;
    }
    Base(int i) { cout << i <<
    "Create Base" << endl;
    }
    ~Base() { cout <<
    "drop base " << name << endl;
    }
    void BaseFun() { cout <<
    "call BaseFun\n";
    }
    //一个int占4个字节,以下三个int,共占12字节
    int index{
    0
    };
    int x{
    0
    };
    int y{
    0
    };
    string name{
    "BaseName"
    };
    void Test() { cout <<
    "BaeTest" << endl;
    }
    protected://自己和派生类
    int pid{
    0
    };
    void PFunc() {
    cout <<
    "Base::PFunc called" << endl;
    };
    private:
    int pri{
    0
    };
    };
    //派生类A继承了Base成员变量和函数
    class A
    :public Base
    {
    public://默认调用无参构造
    A() :Base(100)//设置选用不同的基类构造函数
    { cout <<
    "create A" <<name<< endl;
    }
    ~A() { cout <<
    "drop A" <<name<< endl;
    }
    void AFunc() { cout <<
    "Afunc" << endl;
    }
    void Test() { cout <<
    "Atest" << endl;
    }
    int a_index{
    0
    };
    string name{
    "AName"
    };
    //派生类重新定义name
    };
    //保护继承Base的public变派生类的protected
    class ProClass
    :protected Base
    {
    public:
    ProClass() {
    this->index++;
    this->pid++;
    PFunc();
    }
    int pro_index{
    0
    };
    };
    class ProClassChild
    :public ProClass
    {
    public://可以访问Base的pub和pro
    ProClassChild() {
    this->
    PFunc();
    }
    };
    //私有继承
    class PriClass
    :private Base
    {
    public:
    PriClass() {
    this->
    PFunc();
    }
    };
    class PriClassChild
    :public PriClass
    {
    //不能访问Base中任何成员和方法
    };
    int main()
    {
    Base b;
    cout <<
    sizeof(b) <<
    ":" <<
    &b << endl;
    //12字节,没问题
    {
    cout <<
    "======================A begin====================" << endl;
    A a1;
    a1.Test();
    a1.Base::Test();
    }
    cout <<
    "======================A end====================" << endl;
    /*cout << "======================A===================="<<endl;
    A a1;
    a1.index++;
    //派生类访问基类的成员变量和函数
    cout << a1.index << endl;
    cout << "调用函数:" << endl;
    a1.BaseFun();
    a1.AFunc();*/
    {
    ProClass pc;
    pc.pro_index;
    }
    system("pause");
    }

继承的基本概念

继承允许我们根据一个已有的类(基类或父类,如 Base)来定义一个新的类(派生类或子类,如 A, ProClass)。它的主要目的是实现代码的重用和功能扩展。派生类自动获得基类的所有成员(变量和函数),并可以添加自己新的成员,或者修改基类成员的行为(通过重写,但本例未展示)。

  • 代码体现: 类 A 通过 : public Base 语法公开继承了 Base 的所有 public 和 protected 成员。

类成员的访问控制

  • public (公有): 可以被任何函数访问。
  • protected (保护): 只能被这个类自身和它的派生类访问。外部代码无法访问。例如 Base 中的 pid 和 PFunc(),A 和 ProClass 的内部可以访问它们,但 main 函数中不行。
  • private (私有): 只能被这个类自身访问。即使是它的派生类也无法访问。例如 Base 中的 pri,只有 Base的成员函数能访问它,A 完全不知道它的存在。

继承方式

代码体现:

  • class A : public Base -> A 的对象在 main 中可以调用 BaseFun() 和访问 index。
  • class ProClass : protected Base -> ProClass 的对象在 main 中不能调用 BaseFun() 或访问 index(因为它们变成了 protected),但其派生类 ProClassChild 可以。
  • class PriClass : private Base -> PriClass 的对象在 main 中不能访问 Base的任何成员,其派生类 PriClassChild 也不能。

派生类的内存模型

一个派生类对象的内存包含两部分:

  • 基类子对象 (Base subobject): 继承自基类的所有数据成员。
  • 派生类部分: 派生类自己定义的新数据成员。
    代码体现:
  • sizeof(b) 打印 40(在64位系统上,string 通常占32字节,3个 int 占12字节,内存对齐到8的倍数可能是40字节)。
  • A a1; 的大小会比 Base 更大,因为它包含了 Base 的所有成员 (index, x, y, name) 再加上自己的成员 (a_index, name)。注意,派生类中与基类同名的成员变量是两个不同的变量,存放在内存的不同位置。

构造与析构的顺序

对象的创建和销毁遵循严格的顺序,这是由编译器自动管理的。

  • 构造顺序 (Construction Order):

基类部分: 调用基类的构造函数。
派生类部分: 调用派生类的构造函数。
输出: create base -> create A

  • 析构顺序 (Destruction Order): 与构造顺序完全相反。

派生类部分: 调用派生类的析构函数。
基类部分: 调用基类的析构函数。
输出: drop A -> drop base

名字遮蔽 (Name Hiding)

如果派生类中定义了与基类同名的成员(变量或函数),那么基类中的那个成员会被“遮蔽”起来。

  • 在派生类中,直接使用名字默认访问的是派生类自己的成员。如果需要访问被遮蔽的基类成员,需要使用作用域解析运算符 ::,例如 a1.Base::name。

  • 代码体现: Base 和 A 都有一个 string name;。在 A 的对象 a1 中,a1.name 访问的是 A::name (“AName”),而要访问基类的名字则需要 a1.Base::name (“BaseName”)。

基类不同构造函数的处理

当基类有多个构造函数时,派生类需要明确指定调用哪一个基类构造函数。这通过在派生类构造函数的初始化列表中调用基类构造函数来实现。

#include <iostream>
  #include <string>
    using namespace std;
    class Base
    {
    public:
    // 默认构造函数
    Base() : x(0), y(0), name("Default") {
    cout <<
    "Base default constructor" << endl;
    }
    // 带参数的构造函数
    Base(int x, int y, string name) : x(x), y(y), name(name) {
    cout <<
    "Base parameterized constructor" << endl;
    }
    // 拷贝构造函数
    Base(const Base& other) : x(other.x), y(other.y), name(other.name) {
    cout <<
    "Base copy constructor" << endl;
    }
    void display() {
    cout <<
    "Base: x=" << x <<
    ", y=" << y <<
    ", name=" << name << endl;
    }
    protected:
    int x, y;
    string name;
    };
    class Derived
    : public Base {
    public:
    // 派生类默认构造函数,隐式调用基类默认构造函数
    Derived() : z(0) {
    cout <<
    "Derived default constructor" << endl;
    }
    // 派生类构造函数,显式调用基类带参数的构造函数
    Derived(int x, int y, string name, int z) : Base(x, y, name), z(z) {
    cout <<
    "Derived parameterized constructor" << endl;
    }
    // 派生类拷贝构造函数,显式调用基类拷贝构造函数
    Derived(const Derived& other) : Base(other), z(other.z) {
    cout <<
    "Derived copy constructor" << endl;
    }
    void display() {
    Base::display();
    cout <<
    "Derived: z=" << z << endl;
    }
    private:
    int z;
    };
    int main() {
    cout <<
    "=== 创建派生类默认对象 ===" << endl;
    Derived d1;
    d1.display();
    cout <<
    "\n=== 创建派生类参数化对象 ===" << endl;
    Derived d2(10, 20, "Test", 30);
    d2.display();
    cout <<
    "\n=== 创建派生类拷贝对象 ===" << endl;
    Derived d3 = d2;
    d3.display();
    return 0;
    }
posted @ 2025-09-09 16:11  wzzkaifa  阅读(8)  评论(0)    收藏  举报