C++继承

继承的主要作用:减少代码的数量

class A : public B;
其中A称为子类/派生类,B称为父类/基类

派生类中的成员,包含两大部分
一类是从基类继承过来的,一类是自己增加的成员。

继承方式

类中变量的分类

继承方式分为:公有继承、保护继承、私有继承
类中的变量分为:public\protected\private

#include <iostream>
using namespace std;
class Base1
{
public:
    int m_A = 1;
    void func1()
    {
        cout<<"m_A:"<<m_A<<endl;
        cout<<"m_B:"<<m_B<<endl;
        cout<<"m_C:"<<m_C<<endl;
    }
protected:
    int m_B = 2;
private:
    int m_C = 3;
};
int main()
{
    Base1 base1;
    base1.func1();
    cout<<"类外可以访问public变量:"<<base1.m_A<<endl;
    cout<<"类外不可以访问protected变量:"<<endl;
    cout<<"类外不可以访问private变量:"<<endl;
}

可见:
public成员类内、类外都可以访问。
protected/private成员类内可以访问、类外不可以访问。其两者的主要区别是在继承上。

公有继承

父类public---->子类public
父类protected---->子类protected
父类private---->子类无法访问

#include <iostream>
using namespace std;
class Base1
{
public:
    int m_A = 1;
protected:
    int m_B = 2;
private:
    int m_C = 3;
};
class Son1: public Base1
{
public:
    void test_son1()
    {
        cout<<"父类的public成员:"<<m_A<<endl;
        cout<<"父类的protected成员:"<<m_B<<endl;
        cout<<"父类的private成员不可以访问:"<<endl;
    }
};
int main()
{
    Son1 son1;
    son1.test_son1();
    cout<<"类外可以访问父类的public变量:"<<son1.m_A<<endl;
    cout<<"类外不可以访问父类的protected变量:"<<endl;
    cout<<"类外不可以访问父类的private变量:"<<endl;
}

保护继承

父类public---->子类protected
父类protected---->子类protected
父类private---->子类无法访问

#include <iostream>
using namespace std;
class Base1
{
public:
    int m_A = 1;
protected:
    int m_B = 2;
private:
    int m_C = 3;
};
class Son1: protected Base1
{
public:
    void test_son1()
    {
        cout<<"父类的public成员:"<<m_A<<endl;
        cout<<"父类的protected成员:"<<m_B<<endl;
        cout<<"父类的private成员不可以访问:"<<endl;
    }
};
int main()
{
    Son1 son1;
    son1.test_son1();
    cout<<"类外不可以父类的访问public变量:"<<endl;
    cout<<"类外不可以父类的访问protected变量:"<<endl;
    cout<<"类外不可以父类的访问private变量:"<<endl;
}

保护继承

父类public---->子类private
父类protected---->子类private
父类private---->子类无法访问

#include <iostream>
using namespace std;
class Base1
{
public:
    int m_A = 1;
protected:
    int m_B = 2;
private:
    int m_C = 3;
};
class Son1: private Base1
{
public:
    void test_son1()
    {
        cout<<"父类的public成员:"<<m_A<<endl;
        cout<<"父类的protected成员:"<<m_B<<endl;
        cout<<"父类的private成员不可以访问:"<<endl;
    }
};
int main()
{
    Son1 son1;
    son1.test_son1();
    cout<<"类外不可以父类的访问public变量:"<<endl;
    cout<<"类外不可以父类的访问protected变量:"<<endl;
    cout<<"类外不可以父类的访问private变量:"<<endl;
}

需要注意:父类的private成员也被子类继承过去了,只是编译器给隐藏起来了,访问不到。

父类、子类的构造、析构顺序

父类构造----子类构造----子类析构----父类析构

#include <iostream>
using namespace std;
class Base1
{
public:
    Base1(){cout<<"父类构造函数"<<endl;}
    ~Base1(){cout<<"父类析构函数"<<endl;}
};
class Son1: private Base1
{
public:
    Son1(){cout<<"子类构造函数"<<endl;}
    ~Son1(){cout<<"子类析构函数"<<endl;}
};
int main()
{
    Son1 son1;
    return 0;
}

同名成员的处理

继承过程中如果出现同名成员,默认调用子类中的成员。如果想调用父类中的成员,需要加上作用域。

#include <iostream>
using namespace std;
class Base1
{
public:
    int m_A = 100;
    void func1(){
        cout<<"父类中的func1函数<<endl;"<<endl;
    }
    void func1(int value){
        cout<<"父类中的func1(value)函数<<endl;"<<endl;
    }
};
class Son1: public Base1
{
public:
    int m_A = 200;
    void func1(){
        cout<<"子类中的func1函数<<endl;"<<endl;
    }
};

int main()
{
    Son1 son1;
    // 默认调用子类中的成员
    son1.m_A = 300;
    cout<<son1.m_A<<endl;
    son1.func1();
    son1.func1(10); // 错误,父类中的同名成员函数会被隐藏
    // 如果想调用父类中的成员的话,需要加上一个作用域
    cout<<son1.Base1::m_A<<endl;
    son1.Base1::func1();
    son1.Base1::func1(10);
}
  1. 子类对象可以直接访问到子类中同名成员
  2. 子类对象加作用域可以访问到父类同名成员
  3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

虚继承

虚继承一般发生在菱形继承的情况下,即:
在这里插入图片描述在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B–>D 这条路径,还是来自 A–>C–>D 这条路径。下面是菱形继承的具体实现:

#include <iostream>
#include <string>
using namespace std;
// 间接基类
class Animal
{
public:
    string namea = "Animal";
};
// 直接基类
class Sheep: public Animal
{
public:
    string nameb = "Sheep";
};
// 直接基类
class Tuo: public Animal
{
public:
    string namec = "Tuo";
};
class SheepTuo: public Sheep, public Tuo
{
public:
    string named = "SheepTuo";
};
int main()
{
    SheepTuo sheeptuo;
    // 在两条不同的路径上给namea赋值
    sheeptuo.Sheep::namea = "1";
    sheeptuo.Tuo::namea = "2";
    cout<<sheeptuo.Sheep::namea<<endl;
    cout<<sheeptuo.Tuo::namea<<endl;
    // 错误,编译器不知道namea是从那条路径获得的
    // cout<<sheeptuo.namea<<endl;
}

此时就要用到虚继承:
虚继承:表示一个类做出声明,愿意共享他的基类。这个基类就叫做虚基类。

在这里插入图片描述在上图中,B,C为虚继承,表示愿意共享基类A。其中A称为虚基类。此时派生类D中只会含有一个间接基类A中的元素。

#include <iostream>
#include <string>
using namespace std;
// 间接基类
class Animal
{
public:
    string namea = "Animal";
};
// 直接基类
class Sheep: virtual public Animal
{
public:
    string nameb = "Sheep";
};
// 直接基类
class Tuo: virtual public Animal
{
public:
    string namec = "Tuo";
};
class SheepTuo: public Sheep, public Tuo
{
public:
    string named = "SheepTuo";
};
int main()
{
    SheepTuo sheeptuo;
    // 此时两条路径上的输入会同时影响namea
    // 因为此时namea被两个类共享
    sheeptuo.Sheep::namea = "1";
    sheeptuo.Tuo::namea = "2";
    // 次数均为2
    cout<<sheeptuo.Sheep::namea<<endl;
    cout<<sheeptuo.Tuo::namea<<endl;

    // 不会报错,此时sheeptuo中只包含一个namea
    cout<<sheeptuo.namea<<endl;
}

虚继承的关键在于共享。虚继承的两个类愿意共享基类中的成员变量

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值