C++继承

本文介绍了C++中的类继承机制,包括基类和派生类的概念,访问修饰符(public,protected,private)的作用,以及继承中构造函数、函数重写和变量名称冲突的处理。
摘要由CSDN通过智能技术生成
        

概述

C++提供了比修改代码更好的方法来扩展和修改类,这种方法叫做“类继承”,它可以从已有的类——派生出新的类。派生类继承了原有类(称为基类)的特征,包括方法。

一、基类

        从一个类派生出另一个类的时候,原始类称为基类,继承类称为派生类。 

下面看一个基本代码

#include <iostream>

using namespace std;

class Base
{
public:
    int mA = 1;
protected:
    int mB = 2;
private:
    int mC = 3;
};

Base即为一个基类,在Base类当中存在三个变量处在三种访问修饰符之中:

public(公有的)、protected(受保护的)、private(私有的),这三个访问修饰符,用于修饰类的成员(属性和方法)的可见性:

public 的类成员,可以在任何地方被访问(任何地方可见)。
protected 的类成员,可以在其自身、子类和父类的内部访问。
private 的类成员,只能在其定义的类内部访问。

二、继承

        图书管理系统当中,我们设计一个用户角色Base基类,当我们需要重复使用Base类当中的内容,但需要使用新添加的内容时,往往会选择重新写代码。与其从零开始,不如从Base类派生出一个新类。

2.1初识继承

通过继承派生出的类通常比设计新类容易的多。

1.可以在已有类的基础上添加功能,如:对数组类可以添加数学运算。

2.可以给类添加数据。如:对字符串,可以派生出一个类,并添加指定字符串显示颜色的数据成员。

3.可以修改类方法的行为:如:对与代表提供给乘客服务的Passenger类,可以派生出提供更高级别服务的FirstClassPassenger类。

#include <iostream>

using namespace std;

class Base
{
public:
    int mA = 1;
protected:
    int mB = 2;
private:
    int mC = 3;
};

/*
Base 类是Son的一个public修饰父类
Son类是Base类的一个子类,或者可以认为Son类是Base类 派生类
*/

class Son :public Base
{
public :
    int nA =1;
protected:
    int nB =2;
private:
    int nC = 3;
};


int main(int argc, char const *argv[])
{
    Son *s = new Son;
    
    cout<<" mA : "<<s->mA <<endl;
    cout<<" nA : "<<s->nA <<endl;
    return 0;
}

运行结果:

2.2继承权限

在代码当中我们可以看到,Son类继承父类的时候有出现了访问修饰符对所继承的父类进行修饰。

class Son :public Base

在这种情况下,我们在主函数当中访问父类中的内容、子类中的内容时,会发现报错:

int main(int argc, char const *argv[])
{
    Son *s = new Son;

    cout<<" mA : "<<s->mA <<endl;

    cout<<" mB :"<<s->mB <<endl;

    cout<<" mC :"<<s->mC <<endl;

    cout<<"nA : "<<s->nA <<endl;

    cout <<"nB : "<<s->nB << endl;

    cout <<"nC : "<<s->nC << endl;
    return 0;
}

代码当中的这四行报错。

报错原因:

        首先:public:类内,子类,类外,都可以使用。
                   protected:类内,子类,可以使用,类外无法使用。
                   private: 类内,可以使用,子类,类外无法使用。

        根据三个访问修饰符所作用的范围之后,我们可以明白代码当中mB、mC所属范围便无法在主函数当中访问,故无法访问。

(1)当前情况下,mB 属于 Base 类中的 protected 修饰 成员变量,同时使用 public 方式继承

子类对象无法在类外调用 mB

(2)当前情况下,mC 属于 Base 类中的 private 修饰 成员变量,同时使用 public 方式继承

子类对象无法使用 mC

2.3继承权限组合

        nB、nC在class Son当中,Son所继承的Base其访问修饰符为public,思考若此处的public为其他情况时,访问子类当中的变量会出现什么样的情况。

/*
public 继承方式,父类中的成员权限修饰符变化
    public-》public
    protected-》protected
    private 无法继承
*/
class Son1 :public Base
{
public:
    void test()
    {
        cout <<mA <<endl;
        cout <<mB <<endl;
        cout <<mC <<endl;

        test1();
        test2();
        test3();
    }

};

此处代码报错:

原因:mC以及test3()在父类当中被private修饰。

/*
protected 继承方式,父类当中的成员权限修饰符编号
*/
class Son2 : protected Base
{
public:
    void test()
    {
        cout<< mA <<endl;
        cout<< mB <<endl;
        cout<< mC <<endl;

        test1();
        test2();
        test3();  
    }

};

此处代码报错:

原因:mC以及test3()在父类当中被private修饰。

class Son3 : private Base
{
public:
    void test()
    {
        cout<< mA <<endl;
        cout<< mB <<endl;
        cout<< mC <<endl;

        test1();
        test2();
        test3();  
    }   
    }
};

同样的,此处的mC与test3都报错:

#include <iostream>

using namespace std;

class Base
{
public:
    int mA = 1;
    void test1() { cout << "test1 function" << endl; }

protected:
    int mB = 2;
    void test2() { cout << "test2 function" << endl; }

private:
    int mC = 3;
    void test3() { cout << "test3 function" << endl; }
};

class Son1 : public Base
{
public:
    void test()
    {
        cout << mA << endl;
        cout << mB << endl;
        // cout << mC << endl;

        test1();
        test2();
        // test3();
    }
};

class Son2 : protected Base
{
public:
    void test()
    {
        cout << mA << endl;
        cout << mB << endl;
        // cout << mC << endl;

        test1();
        test2();
        // test3();
    }
};

class Son3 : private Base
{
public:
    void test()
    {
        cout << mA << endl;
        cout << mB << endl;
        // cout << mC << endl;

        test1();
        test2();
        // test3();
    }
};

int main(int argc, char const *argv[])
{
    Son1 *s1 = new Son1;
    cout << s1->mA << endl;

    Son2 *s2 = new Son2;
    // cout << s2->mA << endl;

    Son3 *s3 = new Son3;
    // cout << s3->mA << endl;
    return 0;
}

总结:

继承对应权限修饰符\原修饰符publicprotectedprivate
publicpubilcprotected无法继承
protectedprotectedprotected无法继承
privateprivateprivate无法继承

三、继承中的其他函数

3.1继承中的构造函数及其执行顺序

以下代码创建了一个父类、一个子类、以及一个子类的子类,子类继承父类的修饰符全部为public

#include<iostream>
using namespace std;
class Base
{
public:
    Base()
    {
        cout<<"Base类构造函数"<<endl;
    }
    ~Base()
    {
        cout<<"Base 类析构函数"<<endl;
    }

};

class Son: public Base
{
public:
    Son()
    {
        cout<<"son 类构造函数 "<<endl;
    }
    ~Son()
    {
        cout<<"son 类析构函数 "<<endl;
    }

};


class GrandSon :public Son
{
public:

    GrandSon()
    {
        cout<<" GrandSon 类构造函数 "<< endl;

    }
     ~GrandSon()
    {
        cout<<" GrandSon 类析构函数 "<< endl;

    }
};

通过下面的主函数来调用上面的三个类

int main()
{
    Son *s1 = new Son();

    cout << "------------------------------------------" << endl;
    delete s1;

    cout << "------------------------------------------" << endl;
    GrandSon *gs = new GrandSon();
   
    cout << "------------------------------------------" << endl;
    delete gs;

    return 0;
}

以下为执行结果:

分析:执行下面这一行代码的时候,我们发现结果当中不仅有”son类构造函数“这一行输出还有”Base类构造函数“

Son *s1 = new Son();

同样的,在下面这一行代码执行的时候,不仅出现了本身的构造函数结果,还出现了son类和Base类的构造函数

GrandSon *gs = new GrandSon();

原因:Base类可以提供给Son类使用的内容,但需要通过Base类的构造函数进行初始化

,其内存逻辑空间展示如下图

图:Son类占用的内存空间

总结:构造函数没有创建对象的能力,创建对象都是通过new+构造函数形式进行创建的。构造函数的用于仅仅是提供数据类型和初始化申请内存空间。

        Base构造函数早于Son构造函数执行,是为了初始化Base类空间提供给Son类数据的内存空间。【有其父有其子】

3.2继承中变量名称冲突

class Base
{
public:
    int num;
};

class Son : public Base
{
public:
    int num;

    void test() 
    {
        //int Son :: num
        cout << num << endl;

        //int Base::num
        cout << Base::num << endl;
    }
};

当子类当中的函数调用存在与子类与父类当中相同名称变量的时候,编译器会考虑就近原则方式进行数据匹配,首选是Son类当中的num数据。

当需要使用Base中的num时,需要利用::作用域运算符限制当前变量的作用范围。

3.3继承中的函数(重写)

来继续看一段代码:

#include <iostream>
using namespace std;

class Father
{
public:
    void game() { cout << "黄金矿工" << endl; }
    void job() { cout << "机械工程师" << endl; }
};

class Son : public Father
{
public:
    void game() { cout << "PUBG LOL 古剑奇谭 COD(Call Of Duty)" << endl; }
    void job() { cout << "讲课的!" << endl; }
};

int main(int argc, char const *argv[])
{
    Son *s = new Son;
    s->job();
    s->game();

    return 0;
}

这段代码当中子类Son通过public的方式继承了父类Father,二者类内的函数其修饰符相同,都为public、并且函数名、参数列表相同,唯一不同的是输出内容不同。

代码运行之后得到以下结果:

由结果可知:

(1)子类可以通过public继承得到父类中public修饰函数,类外调用父类的函数有可能无法满足子类的特征需求,此时就需要进行父类函数的重写(Override)。

(2)函数的重写Override

                存在必要的继承关系

                要求子类重写父类的函数,函数声明必须一致

                可以按照子类要求完成函数体内容实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值