c++ 继承

继承: 从已有的类产生新类的方式,通过继承新的类具有原来类的所有的方法和属性;
     原来的类     新的类
      基类        派生类
      父类        子类

单继承: 由一个基类产生一个派生类
多继承: 由多个基类产生一个派生类

单继承:
class 类名 : 继承方式 基类
{
};
类的继承(派生)方式包括: private(私有继承), protected(保护继承), public(公有继承)
#include <iostream>

using namespace std;

class Base
{
public:
    int num;
public:
    Base() : num(0),
    {}
    Base(int n) : num(n)
    {}
    ~Base()
    {}
    void show()
    {
        cout << "num = " << num << endl;
    }
};

class Drivded : public Base
{

};

int main()
{
    Drivded obj;
    obj.show();
    cout << "obj.num = " << obj.num << endl;
    
    return 0;
}
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> ./test
num = 0
obj.num = 0


不同继承方式下成员访问权限的变化:
         继承方式 private     protected    public
访问权限     
private           不可访问    不可访问     不可访问    
protected         private     protected    protected
public            private     protected    public

在派生类中对于基类成员函数进行重新实现: 通过派生类对象调用的是派生类中重新实现的版本;通过派生类对象.基类名::基类的成员方法的格式可以调用基类中实现的版本
#include <iostream>

using namespace std;

class Base
{
private:
    int prv_num;
protected:
    int pro_num;
public:
    int pub_num;
public:
    Base() : prv_num(0), pro_num(0), pub_num(0)
    {}
    Base(int n1, int n2, int n3) : prv_num(n1), pro_num(n2), pub_num(n3)
    {}
    ~Base()
    {}
    void show()
    {
        cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl;
        cout << "prv_num = " << pub_num << endl;
    }
};

class Drivded : public Base
{
private:
    int num;
public:
    void test()
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl; 
        cout << "prv_num = " << pub_num << endl;
    }

    void show()
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "D: prv_num = " << pro_num << endl;
        cout << "D: prv_num = " << pub_num << endl;
    }
};

class Drivded1 : public Drivded
{
public:
    void test()
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl;
        cout << "prv_num = " << pub_num << endl;
    }
};

int main()
{
    Drivded obj;
    obj.show();
    obj.Base::show();  //通过派生类对象.基类名::类的成员方法的格式可以调用基类中实现的版本

    cout << "obj.num = " << obj.pub_num << endl;
    cout << sizeof(Base) << ", " << sizeof(Drivded) <<endl;
    
    return 0;
}
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> g++ .\单继承实例.cpp -o test
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> ./test
D: prv_num = 0
D: prv_num = 0
prv_num = 0
prv_num = 0
prv_num = 0
obj.num = 0
12, 16

在派生类中对基类的成员方法进行重载: 通基类对象可以直接访问派生类中重载的版本,但不能直接访问基类中实现的版本;通过派生类对象.基类名::类的成员方法的格式可以调用基类中实现的版本
/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2023-08-03 14:21:48
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-08-03 15:14:33
 * @FilePath: \vscode\cpp_source\CPP_202308\CPP_05 继承\单继承实例.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>

using namespace std;

class Base
{
private:
    int prv_num;
protected:
    int pro_num;
public:
    int pub_num;
public:
    Base() : prv_num(0), pro_num(0), pub_num(0)
    {}
    Base(int n1, int n2, int n3) : prv_num(n1), pro_num(n2), pub_num(n3)
    {}
    ~Base()
    {}
    void show()
    {
        cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl;
        cout << "prv_num = " << pub_num << endl;
    }
};

class Drivded : public Base
{
private:
    int num;
public:
    void test()
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl; 
        cout << "prv_num = " << pub_num << endl;
    }

    void show(int u)
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "D: prv_num = " << pro_num << endl;
        cout << "D: prv_num = " << pub_num << endl;
    }
};

class Drivded1 : public Drivded
{
public:
    void test()
    {
        //cout << "prv_num = " << prv_num << endl;
        cout << "prv_num = " << pro_num << endl;
        cout << "prv_num = " << pub_num << endl;
    }
};

int main()
{
    Drivded obj;
    obj.show(8);
    //obj.show(); //在派生类中对基类成员的
    obj.Base::show();  //通过派生类对象.基类名::类的成员方法的格式可以调用基类中实现的版本

    cout << "obj.num = " << obj.pub_num << endl;
    cout << sizeof(Base) << ", " << sizeof(Drivded) <<endl;
    
    return 0;
}

overwrite: 重写: 在派生关系中,在派生类中对于基类的成员方法保持和基类的原型进行重新实现(函数原型相同,函数的函数体不同)
overload: 重载: 在同一范围内的同名不同参数的两个版本的函数

覆盖: 派生类对基类的成员方法进行重写的时候,在派生类中派生类重写的版本会覆盖基类中实现的版本(通过派生类对象是不能直接访问被覆盖的成员方法)
隐藏: 派生类对基类的成员方法进行重载的时候,在派生类中派生类重载的版本会隐藏基类中实现的版本(通过派生类对象是不能直接访问被覆盖的成员方法)

派生类和基类之间的关系:
a. 派生类是基类的具体化
b. 派生类是基类定义的延续
c. 派生类是基类的组合

单继承: 单继承是指派生类有且只有一个基类的情况,在单继承中,每个类可以有多个派生类,但是每个派生类只能有一个基类,从而形成树形结构。
#include <iostream>
#include <cstring>

using namespace std;

//交通工具类
class Vehicle
{
protected:
    int speed; //行驶速度
    int total; //载客量
public:
    Vehicle() : speed(0), total(0)
    {
        cout << "交通工具类的无参构造函数" << endl;
    }
    Vehicle(int sp, int to) : speed(sp), total(to)
    {
        cout << "交通工具类的带参数构造函数" << endl;
    }

    ~Vehicle()
    {
        cout << "交通工具类的析构函数" << endl;
    }

};

class Car : public Vehicle
{
private:
    float air;  //排量
public:
    Car()
    {
        cout << "汽车类的无参构造函数" << endl;
    }
    Car(int sp, int to, float ai)
    {
        cout << "汽车类的带参数的构造函数" << endl;
    }
    ~Car()
    {
        cout << "汽车类的析构函数" << endl;
    }
};

int main()
{
    Car benz;
    
    return 0;
}
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> g++ .\单继承.cpp -o test
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> ./test 
交通工具类的无参构造函数
汽车类的无参构造函数
汽车类的析构函数
交通工具类的析构函数

派生类对象在构建的时候会先调用基类的构造方法(默认的会调用基类的无参构造)来构造派生类中从基类继承的部分(派生类中包含的基类对象),然后再调用自己的构造方法构造自己独有的部分
派生类对象的析构是先析构自己独有的部分,然后再调用基类的析构方法释放从基类继承的部分
#include <iostream>
#include <cstring>

using namespace std;

//交通工具类
class Vehicle
{
protected:
    int speed; //行驶速度
    int total; //载客量
public:
    Vehicle() : speed(0), total(0)
    {
        cout << "交通工具类的无参构造函数" << endl;
    }
    Vehicle(int sp, int to) : speed(sp), total(to)
    {
        cout << "交通工具类的带参数构造函数" << endl;
    }

    ~Vehicle()
    {
        cout << "交通工具类的析构函数" << endl;
    }

};

class Car : public Vehicle
{
private:
    float air;  //排量
public:
    Car()
    {
        cout << "汽车类的无参构造函数" << endl;
    }
    Car(int sp, int to, float ai) //不能在初始值表中直接初始化从基类继承的成员,只能在函数体内赋值
    {
        speed = sp;
        total = to;
        air = ai;
        cout << "汽车类的带参数的构造函数" << endl;
    }
    ~Car()
    {
        cout << "汽车类的析构函数" << endl;
    }

    void run()
    {
        cout << "汽车载客" << total << "人, 以" << speed << "公里/小时行驶在高速公路上" << endl;
    }
};

int main()
{
    //Car benz;
    Car bmw(130, 5, 2.8);
    bmw.run();

    return 0;
}
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> g++ .\单继承.cpp -o test
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> ./test
交通工具类的无参构造函数
汽车类的带参数的构造函数
汽车载客5人, 以130公里/小时行驶在高速公路上
汽车类的析构函数
交通工具类的析构函数

在派生类的构造函数的初始值表中可以指定调用的基类构造函数的版本
Car(int sp, int to, float ai) : Vehicle(sp, to), air(ai)
 {
        cout << "汽车类的带参数的构造函数" << endl;
}

在派生关系中,基类的构造方法和析构方法不能够被派生类继承,而是C++使用一种机制来使得派生类对象构建的时候调用基类的构造方法初始化基类继承部分,在析构的时候,调用基类的析构方法释放基类继承部分

多继承
#include <iostream>
#include <cstring>

using namespace std;

//交通工具类
class Vehicle
{
protected:
    int speed; //行驶速度
    int total; //载客量
public:
    Vehicle() : speed(0), total(0)
    {
        cout << "交通工具类的无参构造函数" << endl;
    }
    Vehicle(int sp, int to) : speed(sp), total(to)
    {
        cout << "交通工具类的带参数构造函数" << endl;
    }

    ~Vehicle()
    {
        cout << "交通工具类的析构函数" << endl;
    }

};

class Car : public Vehicle
{
private:
    float air;  //排量
public:
    Car()
    {
        cout << "汽车类的无参构造函数" << endl;
    }
    Car(int sp, int to, float ai) : Vehicle(sp, to), air(ai)
    {
        cout << "汽车类的带参数的构造函数" << endl;
    }
    ~Car()
    {
        cout << "汽车类的析构函数" << endl;
    }

    void run()
    {
        cout << "汽车载客" << total << "人, 以" << speed << "公里/小时行驶在高速公路上" << endl;
    }
};

class Boat : public Vehicle
{
public:
    int water;  //排水量
public:
    Boat() : water(0)
    {
        cout << "轮船的无参构造" << endl;
    }
    Boat(int sp, int to, int wa) : Vehicle(sp, to), water(wa)
    {
        cout << "轮船的带参数构造函数" << endl;
    }
    ~Boat()
    {
        cout << "轮船的析构函数" << endl;
    }
};

class Amphibibous : public Car, public Boat
{
public:
    Amphibibous()
    {
        cout << "水陆两栖车的无参构造函数" << endl;
    }
    Amphibibous(int sp, int to, float ai, int wa)
    {
        cout << "水陆两栖车的带参数构造函数" << endl;
    }
    ~Amphibibous()
    {
        cout << "水陆两栖车的析构函数" << endl;
    }
};

int main()
{
    //Car benz;
    //Car bmw(130, 5, 2.8);
    //bmw.run();

    cout << "sizeof(Amphibibous) = " << sizeof(Amphibibous) << endl;
    Amphibibous K007(50, 10, 6.0f, 1000);

    return 0;
}
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> g++ .\单继承.cpp -o test
PS E:\LinuxShared\vscode\cpp_source\CPP_202308\CPP_05 继承> ./test
sizeof(Amphibibous) = 24  
交通工具类的无参构造函数  
汽车类的无参构造函数      
交通工具类的无参构造函数  
轮船的无参构造
水陆两栖车的带参数构造函数
水陆两栖车的析构函数      
轮船的析构函数
交通工具类的析构函数
汽车类的析构函数
交通工具类的析构函数

注意: 在多继承中,多个基类构造函数的调用顺序和派生类定义中指定的派生关系中基类的出现的先后顺序一致
如果Amphibious类的带参数构造函数:
Amphibibous(int sp, int to, float ai, int wa) : Boat(sp, to, wa), Car(sp, to, ai)
{
      cout << "水陆两栖车的带参数构造函数" << endl;
}
则在实例化水陆两栖车的时候会调用轮船和汽车的带参的构造函数

歧义(二义性):
当不同的基类中具有相同的成员的时候,在派生类中这个成员就会出现两个版本,这时通过派生类对象访问该成员的时候就存在二义性;解决的方法可以在派生类中对于该方法进行重新实现(重写或者重载)

虚继承:
在派生类的继承方式中加上virtual关键字
引进虚基类后,派生类(即子类)的对象中只存在一个虚基类的子对象。当一个类有虚基类时,编译系统将为该类的对象定义一个指针成员,让它指向虚基类的子对象。该指针被称为虚基类指针。 

赋值兼容:
    Car benz;
    Car bmw(130, 5, 2.8);

    Vehicle v;
    v = benz; //可以将一个派生类对象赋值给基类对象,实际上是将派生类对象中的基类对象部分赋值给基类对象变量
    //benz = v;
    Vehicle *p;
    p = &benz;  //基类指针指向派生类对象
    //Car *pc = &v;
    Vehicle &a = bmw; //基类引用派生类对象
在继承关系中赋值兼容包括:
a. 基类指针指向派生类对象
b. 基类引用派生类对象
c. 将派生类对象赋值给基类对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值