【C++】继承

基本知识

继承是面向对象三大特性之一(三大特性:封装,继承和派生,多态)。

当一些类之间存在特殊的关系:下级别成员拥有上一级的共性,还有自己的特性。这时可以用继承,减少重复代码。

例子

学生类和工人类都有人(名字、年龄、性别)这个类的共性,而它们都有自己的特性:学生有成绩、工人有水平。这样可以让学生类和工人类继承人类:

class Person
{
public:
    Person(){}
    ~Person(){}
private:
    char* m_name;
    char m_sex;
    int m_age;
};
//class 子类 :继承权限 父类
class Student:public Person
{
public:
    Student(){}
    ~Student(){}
private:
    float m_score;
};
class Worker:public Person
{
public:
    Worker(){}
    ~Worker(){}
private:
    int m_level;
};

子类又叫派生类,父类又叫基类。

继承三步

1.将父类中除了构造和析构之外的内容全盘接收

2.子类改写了父类的方法

3.子类添加自己特有的属性或方法


继承方式:

继承方式有三种:公共继承public、保护继承protected、私有继承private、

注意:

父类私有private会被继承但是子类谁都不能访问

保护protected在子类中可以访问,外界不可访问

继承时的权限是更改父类的public或protected(越变范围越小),外部访问受影响

继承方式影响如下:

public:权限不变 protected:公有变保护、private:保护&公有变私有

例子

公有私有保护继承:

class A
{
public:
    int m_i;
protected:
    int m_j;
private:
    int m_k;
};
class B:public A
{//在内部只能用父类的public&protected
    void printf() {
        m_i = 10;
        m_j = 20;
        //m_k = 30;//错误:父类中的私有成员子类不能使用
    }
};
class C:protected A
{
    void printf() 
    {
        m_i = 10;
        m_j = 20;
        //m_k = 30;//error
    }
};
class D :private A
{
    void printf() {
        m_i = 10;
        m_j = 20;
    //    m_k = 30;//error
    }
};
int main()
{
    cout << sizeof(B)<<endl<<sizeof(C)<<endl<<sizeof(D)<< endl;
            //12                 12                 12          把m_i,m_j,m_k都继承了
    B b;
    C c;
    D d;
    b.m_i = 10;//在外界b只能用public
    //C继承A的时候,将public属性变成protected了,外界不能用它任何东西了
    //D继承A的时候,将public和protected属性变成private了,外界不能访问
}

私有和保护的区别

多层继承:

B通过私有方式继承A,C通过公有方式继承B,C无法使用A内的任何成员

B通过保护方式继承A,C通过公有方式继承B,C可以使用A内的保护成员


构造和析构顺序

如果调用子类,则先调用父类构造,再调用子类构造(先有爸爸再有儿子),析构的顺序与构造顺序相反。

class A
{
public:
    A() { cout << "~A" << endl; }
    ~A() { cout << "~A" << endl; }
};
//:继承权限 基类
class B :public A
{
public:
    B() { cout << "B" << endl; }
    ~B() { cout << "~B" << endl; }
};
int main()
{
    B b;
}

//子类没有权力对继承下来的成员构造或销毁


同名成员处理

当子类与父类出现同名的成员,通过子类对象访问子类或父类中的同名数据:

访问子类同名成员,直接访问;

访问父类同名成员,加作用域。

class A
{
public:
    A():m_i(10) {}
    void fun() { cout << "A的fun" << endl; }
    int m_i;
};
class B :public A
{
public:
    B() :m_i(20) {}
    void fun() { cout << "B的fun" << endl; }
    int m_i;
};
int main()
{
    B b;
    cout << b.m_i << endl << b.A::m_i << endl;
    b.fun();
    b.A::fun();
}

如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(重载的也会被隐藏),如果想访问到父类中被隐藏的同名成员函数,需要加作用域。

继承同名静态成员处理

静态成员在静态区中,不占用类的空间,所有类共享——静态成员函数没有this指针

静态比全局的优点:

1.只有类对象可以访问,可以隐藏,全局不行

2.避免与其他全局变量重复

注意:

可以直接在类中初始化

不能在类初始化列表中初始化

在外部声明时不需要再用static

使用同名静态成员与普通成员一样,通过对象和类名都可以访问。

class A
{
public:
    static int m_i=10;
};
class B :public A
{
public:
    static int m_i=20;
};
int main()
{
//访问A类中m_i——10
    cout<<A::m_i<<endl;
//访问B类中m_i——20
    cout<<B::m_i<<endl;
//通过类名方式访问A类中m_i——10
    cout<<B::A::m_i<<endl;
//访问b对象中m_i——20
    B b;
    cout<<b.m_i<<endl;
    
}

多继承语法

一个类继承多个类

class 子类: 继承方式 父类1, 继承方式 父类2…

多继承可能引发父类中有同名的父类(二义性),这时需要使用作用域。

不建议使用多继承!

class B1
{
public:
    B1(){m_i = 100;};
    int m_i;
};
class B2
{
public:
    B2(){m_i = 200;};
    int m_i;
};
class Son:public B1,public B2
{
public:
    Son(){m_a = 300;m_b = 400;};
    int m_a;
    int m_b;
};
int main()
{
    Son s;
    cout<<s.B1::m_i<<" "<<s.B2::m_i<<endl;//100 200
}

菱形继承

菱形继承(钻石继承):两个派生类继承同一个基类,又有某个类同时继承两个派生类

菱形继承产生的问题:

1.父亲和伯伯都继承了爷爷的东西,当孙子使用时,会产生二义性

2.孙子继承了两份同样的数据(来自爷爷的),但这数据只需要一份

解决方法:

1.二义性加作用域区分

2.虚继承解决两份同样数据

class A
{
public:
    A(int i = 0) :m_a(i) {}
    int m_a;
};
class B:public A
{
public:
    B(int b = 0) :m_b(b) {  }
    int m_b;
};
class C:public A
{
public:
    C(int c = 0) :m_c(c) {  }
    int m_c;
};
class D :public B, public C
{
public:
    D(int d = 0) :m_d(d) {}
    int m_d;
};
void main()
{
    cout << sizeof(D) << endl;//5*4==20,将A的数据继承了两份
}

虚继承

在继承之前加上关键字virtual变为虚继承;

最先的类叫虚基类。

class B:virtual public A

虚继承是继承了一个虚基类指针(vbptr),指向虚基类表,表中存储着虚类的地址(偏移量),使用时在虚基类表中找这个数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

曦樂~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值