C/C++————继承

继承


1.继承是什么?

在 C++ 中,继承(Inheritance) 是面向对象编程(OOP)的核心特性之一,允许一个类从另一个类派生,继承其属性(成员变量)和行为(成员函数),从而实现代码复用多态性子类——派生类,父类——基类


基本语法

class 父类名 {
public:
    int a;
    void show() {
        std::cout << "This is base class" << std::endl;
    }
};

class 子类名 : 继承方式 父类名 {
public:
    int b;
    void display() {
        std::cout << "This is derived class" << std::endl;
    }
};


三种继承方式

继承方式语法示例父类的 public 成员在子类中protected 成员private 成员
public 继承class B : public A保持 public保持 protected不可访问
protected 继承class B : protected A变成 protected保持 protected不可访问
private 继承class B : private A变成 private变成 private不可访问


1)public继承

#include<iostream>
using namespace std;

class base1
{
public:
    int m_a;
protected:
    int m_b;
private:
    int m_c;
};

class son:public base1
{
public:
    void func()
    {
        m_a;//父类中的公共权限成员 到子类中依然是公共权限
        m_b;//父类中的保护权限成员 到子类中依然是保护权限
      //m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到
    }
};

void test_01()
{
    son s1;
    s1.m_a=12;
    cout<<s1.m_a<<endl;
    s1.func();   
}

int main()
{
    test_01();

    return 0;
}

public继承在子类里面,可以对父类public,protected变量进行访问修改

子类外,仅能对public修改,而protected不行,如上代码所示



2)protected继承

#include<iostream>
using namespace std;

class base1
{
public:
    int m_a;
protected:
    int m_b;
private:
    int m_c;
};

class son:protected base1
{
public:
    void func()
    {
        m_a;//父类中的公共权限成员 到子类中变成保护权限
        m_b;//父类中的保护权限成员 到子类中变成保护权限
      //m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到
    }
};

void test_01()
{
    son s1;
    //s1.m_a=12;已变为protected不可访问编辑
    //s1.m_b=20;protected不可访问编辑
}

int main()
{
    return 0;
}

protected继承在子类里面,可以对父类public(变为protected类型),protected变量进行访问修改

子类外,对public,protected都不行(都已是protected类型),如上代码所示



3)private继承

#include<iostream>
using namespace std;

class base1
{
public:
    int m_a;
protected:
    int m_b;
private:
    int m_c;
};

class son:private base1
{
public:
    void func()
    {
        m_a=10;//父类中的公共权限成员 到子类中变成私有权限
        m_b=10;//父类中的保护权限成员 到子类中变成私有权限
      //m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到
    }
};

class gdson:public son
{
public:
    void func()
    {
        //m_a访问不到,已经变为私有
    }
};

int main()
{
    return 0;
}

private继承在子类里面,可以对父类public,protected变量进行访问修改

子类外,对public,protected都不行(都已是private类型)

在对私有继承再继承时,都不能访问并编辑(都已是private类型),如上代码所示



2.继承中构造与析构顺序

在我们学习了三种继承方式,你是否会有疑问?——类中有构造与析构函数,那么继承中他们顺序是怎么样的,这一下小节我们就来探讨一下

#include<iostream>
using namespace std;

class base
{
public:
    base()
    {
        cout<<"父类构造函数"<<endl;
    }
    ~base()
    {
        cout<<"父类析构函数"<<endl;
    }
};

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

void test_01()
{
    son s1;

}

int main()
{
    test_01();
    return 0;
}

输出结果如下:
在这里插入图片描述

我们可以看到顺序是——父->子->子->父



3.继承同名成员处理方式

1)同名成员变量处理

在遇到父子类都有相同名的变量时,该如何正确访问呢,如下代码所示:

class base
{
public:
    base()
    {
        m_a=100;
    }
    int m_a;
};

class son:private base
{
public:
    son()
    {
        m_a=200;
    }
    int m_a;
};

我们先进行简单测试一下:

#include<iostream>
using namespace std;

class base
{
public:
    base()
    {
        m_a=100;
    }
    int m_a;
};

class son:public base
{
public:
    son()
    {
        m_a=200;
    }
    int m_a;
};

void test_01()
{
    son s1;
    cout<<s1.m_a<<endl;

}

int main()
{
    test_01();
    return 0;
}

最后输出结果是200,“那我想访问父类的m_a该怎么做呢?”,其实我们只要加一作用域就可以达到我们想要的效果了

cout<<"子类的数据"<<s1.m_a<<endl;
cout<<"父类的数据"<<s1.base::m_a<<endl;

这样就ok了啊



2)同名成员函数处理

函数处理其实和成员变量处理方式一样,加个作用域就可以

son s1;
s1.func();//子类函数调用
s1.base::func();//父类函数调用

但是这里要介绍一个容易出现问题的地方:

class base
{
public:
    base()
    {
        m_a=100;
    }
    void func()
    {
        cout<<"父类的函数调用"<<endl;
    }
    void func(int a)
    {
        cout<<"父类的函数调用(int a)"<<endl;
    }
    int m_a;
};

class son:public base
{
public:
    son()
    {
        m_a=200;
    }
    void func()
    {
        cout<<"子类的函数调用"<<endl;
    }
   
    int m_a;
};

void test_01()
{
    son s1;
    s1.func(100);

}

在父类里面我们对func()函数进行了一个有参重载

但是在调用s1.func(100)会出现报错

为什么加了参数还不能定位到父类函数呢?——其实原因就在于子类创建后,会屏蔽一切所有父类同名函数,切记是同名,所以解决方法,再加一个作用域就好啦

son s1;
s1.base::func(100);


小总结

  • 子类可以直接访问,子类中同名成员
  • 子类访问父类同名成员,需加上作用域


4.继承同名静态成员处理方法


1)通过对象访问

就是简单的添加作用域访问

#include<iostream>
using namespace std;

class base
{
public:
    static int m_a;
};
int base:: m_a=100;

class son:public base
{
public:
    static int m_a;
};
int son:: m_a=200;

void test_01()
{
    son s1;
    cout<<s1.m_a<<endl;
    cout<<s1.base::m_a<<endl;
}

int main()
{
    test_01();
    return 0;
}


2)通过类名访问

void test_01()
{
    //通过类名访问
    cout<<son::m_a<<endl;
    cout<<base::m_a<<endl;
    //通过 son 继承的 base 路径访问
    cout<<son::base::m_a<<endl;
}

这就是static特殊的地方,创建了就一直存在,所有在作用域内的代码可以访问同一块地址

小总结

  • 主要就是static可以用类访问,但切记变量类内声明,类外初始化
  • 函数同样的方法可以访问,函数可在直接类内定义

5.菱形继承


如下图所示,在B,C继承A之后,我们D多继承B,C之后,那么我们对于m_a该如何访问并修改呢?

在这里插入图片描述

首先如下代码所示:

#include<iostream>
using namespace std;

class A
{
public:
    int m_a;
};

class B:public A
{};
class C:public A
{};
class D:public B,public C
{};

void test_01()
{
    D d1;
    d1.B::m_a=100;
    d1.C::m_a=300;
    cout<<"B的a:"<<d1.B::m_a<<endl;
    cout<<"C的a:"<<d1.C::m_a<<endl;
}
int main()
{
    test_01();
    return 0;
}

输出结果如下:

在这里插入图片描述


这里其实和第三节方法是一样的,是对同名变量的操作

但是,这里其实是有问题,这样两个变量都是对A的继承,就会造成资源浪费,那我们怎么解决呢?

这里就引出一个新的概念——虚继承

class B:virtual public A
{};
class C:virtual public A
{};

我们只需将B,C加上virtual,就可以解决问题


这时候的完整代码:

#include<iostream>
using namespace std;

class A
{
public:
    int m_a;
};

class B:virtual public A
{};
class C:virtual public A
{};
class D:public B,public C
{};

void test_01()
{
    D d1;
    d1.B::m_a=100;
    d1.C::m_a=300;
    cout<<"B的a:"<<d1.B::m_a<<endl;
    cout<<"C的a:"<<d1.C::m_a<<endl;
}
int main()
{
    test_01();
    return 0;
}

输出结果如下所示:
在这里插入图片描述

可以发现,这时候m_a已经是一个变量了,不会造成出现两个这种情况了


6.总结

这就是我对继承的理解啦!从语法到实际使用,其实并不难,只要多写几次自然就熟悉了。下一篇我会记录下“多态”的使用,尤其是虚函数和虚继承的细节,欢迎继续关注!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值