C++ 继承

1、类的继承

类的继承指的是,新的类从已有的类中获得已有的特性。
新的类叫做派生类,也叫子类,被继承的类叫做基类,也叫做父类。

下面是继承的基本格式

class 派生类:继承方式 基类1,继承方式 基类2,......,继承方式 基类n{
}

在C++中,允许多继承
下面代码段是D以公有继承的方式继承了A,以私有继承的方式继承了B,以保护继承的方式继承了C
三种继承方式的说明会在下文提到

class A{


};

class B{

};

class C{


};

class D:public A,private B,protected C{


};


2、直接继承与间接继承

一个派生类还可以作为基类,让新的类继承它

一个类Line继承了类Point,类Square继承了类Line,那么我们称Line直接继承了Point,Square直接继承了Line,而Square间接继承了Point


3、类的三种继承方式

①公有继承

当类的继承方式为公有继承的时候,基类的公有成员和保护成员的访问权限在派生类中保持不变,而私有成员不可直接访问,即派生类无法直接访问基类的私有成员。

#include<bits/stdc++.h>
using namespace std;
class Point{
    public:
        void initPoint(double x,double y){
            this->x=x;
            this->y=y;
        }
        double getx() const{
           return x;
        }
        double gety() const{
            return y;
        }
    private:
        double x,y;
};

class A:public Point{
    public:
        void initA(double x,double y,double w,double h){
            initPoint(x,y);
            this->w=w;
            this->h=h;
        }
        double geth() const{
            return this->h;
        }
        double getw() const{
            return this->w;
        }
    private:
      double w,h;

};
int main(){
    A test;
    test.initA(1,2,3,4);
    cout<<test.getx()<<" "<<test.gety()<<endl;
    cout<<test.geth()<<" "<<test.getw()<<endl;
    return 0;
}

下面的代码中类A公有继承了类Point,即除了私有成员和构造函数、析构函数以外的东西,全部继承了,并且访问权限与基类中访问权限一样。
在类A的公有函数可以直接调用从类Point继承的initPoint
但是不能直接调用基类的x和y
如果,在派生类中,存在有继承的函数名字相同的函数,那么调用的就是派生类中的函数,而不是基类的,这里可以类比一样变量的生命周期,最里边的起作用,外部的同名变量被屏蔽。

②私有继承

当类的继承方式为私有继承的时候,基类的公有成员和保护成员都会变成派生类的私有成员,而基类的私有成员,派生类无法访问。

#include<bits/stdc++.h>
using namespace std;
class Point{
    public:
        void initPoint(double x,double y){
            this->x=x;
            this->y=y;
        }
        double getx() const{
           return x;
        }
        double gety() const{
            return y;
        }
    private:
        double x,y;
};

class A:private Point{
    public:
        void initA(double x,double y,double w,double h){
            initPoint(x,y);
            this->w=w;
            this->h=h;
        }
        double getxx() const{
            return getx();
        }
        double getyy() const{
            return gety();
        }
        double geth() const{
            return this->h;
        }
        double getw() const{
            return this->w;
        }
    private:
      double w,h;

};
int main(){
    A test;
    test.initA(1,2,3,4);
    // cout<<test.getx()<<" "<<test.gety()<<endl; 错误 
    cout<<test.getxx()<<" "<<test.getyy()<<endl; 
    cout<<test.geth()<<" "<<test.getw()<<endl;
    return 0;
}

在私有继承中,基类的公有成员和保护成员都变成了派生类的私有成员,只有类中的成员可以直接访问,类外的对象不可直接访问私有成员。


③保护继承

当类的继承方式为保护继承的时候,基类的公有成员和保护成员都会变成派生类的保护成员,而私有成员不可访问。

#include<bits/stdc++.h>
using namespace std;
class Point{
    public:
        void initPoint(double x,double y){
            this->x=x;
            this->y=y;
        }
        double getx() const{
           return x;
        }
        double gety() const{
            return y;
        }
    private:
        double x,y;
};

class A:protected Point{
    public:
        void initA(double x,double y,double w,double h){
            initPoint(x,y);
            this->w=w;
            this->h=h;
        }
        double getxx() const{
            return getx();
        }
        double getyy() const{
            return gety();
        }
        double geth() const{
            return this->h;
        }
        double getw() const{
            return this->w;
        }
    private:
      double w,h;

};
int main(){
    A test;
    test.initA(1,2,3,4);
    // cout<<test.getx()<<" "<<test.gety()<<endl; 错误 
    cout<<test.getxx()<<" "<<test.getyy()<<endl; 
    cout<<test.geth()<<" "<<test.getw()<<endl;
    return 0;
}

这里的代码和私有继承那里一样,只不过改了一下继承方式而已。
那么到这里,可能有疑问了,私有继承和保护继承一样吗?

既然两个都存在,那么肯定是不一样的

那么不一样在哪里呢?
根据上述代码,如果是直接继承,那么保护继承和私有继承,确实是一模一样的。
因为直接继承后,不管是保护成员,还是私有成员,都是不允许类外的本类对象直接访问继承的成员的。
那么我们不妨考虑一下,如果是间接继承呢?
此时,在直接继承的派生类中,如果是保护继承,那么如果当前派生类作为新的基类,可以知道,无论以什么形式继承,在新的派生类中类内是可以访问基类的保护成员的,因为保护成员可以被继承!
但是,如果当前派生类是私有继承过来的,那么当前派生类作为基类的话,新的派生类是无法继承到私有成员的!

一般地,如果需要继承的成员,我们把它的属性设为保护成员,而不是私有成员,这样既能实现数据的隐蔽,又方便继承。

下面代码 说明了保护成员有可能被派生类访问,但绝对不会被其他外部使用者访问,如程序的普通函数等等

#include<bits/stdc++.h>
using namespace std;
class A{
    protected: 
        int x;
};
class B:public A{
    public:
        void fun(int d){
            x=d;
        }
};
int main(){
    A a;
    // a.x=5;  错误
    B b;
    b.fun(5); // 正确
    return 0;
}

4、类型兼容规则

在需要基类对象的任何地方,都可以使用公有继承的派生类对象代替
这个其实很好理解,因为公有继承,得到了除构造函数、析构函数外的所有成员(不可直接访问的私有成员,可以在基类中编写get和set函数即可)。

class B{ ... }
class D:public B{ ... }
B b1,*pb1;
D d1;

包括以下三种情况
①派生类的对象可以隐含转换为基类对象

b1=d1;

②派生类的对象可以初始化基类的引用

B &r=d1;

③派生类的指针可以隐含转换为基类的指针

pb1=&d1

派生类的对象可以作为基类对象使用,但是只能使用从基类继承来的成员

类型兼容规则是多态性的重要基础之一


5、构造函数

和普通类一样,如果没有给派生类编写构造函数,编译器会自动加上默认构造函数,默认构造函数会自动调用这个派生类所继承的基类的构造函数。
在派生类中,如果对基类成员进行初始化,需要调用带有参数的构造函数,那么派生类必须编写构造函数

派生类的构造函数格式如下

派生类名字::派生类名字(参数表):基类1(基类1初始化参数),基类2(基类2初始化参数)....
成员对象名1(成员对象名1的初始化参数)....{
		派生类构造函数初始化的其他操作
}

派生类的构造函数执行的调用顺序如下

①调用基类构造函数,按照被继承的顺序从左到右执行
②对派生类所新增的成员初始化,初始化顺序按照在派生类中声明的顺序
③派生类构造函数函数体的部分

下面代码就是一个很好的例子
在执行派生类Test的时候,首先对于三种基类,按照继承的顺序Base2、 Base1 、Base3顺序调用基类的构造函数,然后对于新增的成员对象按照声明的顺序去执行他们的构造函数Base1、 Base2 、Base3,最后执行函数体

#include<bits/stdc++.h>
using namespace std;

class Base1{
    public:
        Base1(int i){
            cout<<"Base 1 "<<i<<endl;
        }
};

class Base2{
    public:
        Base2(int i){
            cout<<"Base 2 "<<i<<endl;
        }
};

class Base3{
    public:
        Base3(){
            cout<<"Base 3 *"<<endl;
        }
};

class Test:public Base2,protected Base1,private Base3{
    public:
        Test(int a,int b,int c,int d):Base1(a),member2(b),member1(c),Base2(d){
               cout<<"Test begin"<<endl;
        }
    private:
        Base1 member1;
        Base2 member2;
        Base3 member3;
};
int main(){
    Test test(1,2,3,4);
    return 0;
}

6、析构函数

我们直到析构函数和构造函数的调用顺序是反过来了,先调用的最后析构,其实就是一个栈,先进后出

#include<bits/stdc++.h>
using namespace std;

class Base1{
    public:
        Base1(int i){
            cout<<"Base 1 "<<i<<endl;
        }
        ~Base1(){
            cout<<"Base 1 over"<<endl;
        }
};

class Base2{
    public:
        Base2(int i){
            cout<<"Base 2 "<<i<<endl;
        }
        ~Base2(){
            cout<<"Base 2 over"<<endl;
        }
};

class Base3{
    public:
        Base3(){
            cout<<"Base 3 *"<<endl;
        }
        ~Base3(){
            cout<<"Base 3 over"<<endl;
        }
};

class Test:public Base2,protected Base1,private Base3{
    public:
        Test(int a,int b,int c,int d):Base1(a),member2(b),member1(c),Base2(d){
                cout<<"Test begin"<<endl<<endl;
        }
        ~Test(){
            cout<<"Test over"<<endl;
        }
    private:
        Base1 member1;
        Base2 member2;
        Base3 member3;
};
int main(){
    Test test(1,2,3,4);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会c语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值