【C++学习二】C++继承

初识C++之 继承

c++作为一门OO语言,怎么能少得了继承?在面向对象语言当中,继承允许我们依据一个类来定义另一个类。继承的特性在于,新的类默认含有继承类的一些属性与方法。这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。

当创建一个类时,我们不再需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类

1. 继承访问权限测试(类内部成员的权限)

c++拥有三种继承权限方式,分别是public, protectprivate

下面我们通过实验来观察一下这三种不同的继承方式有什么不同。首先我们定义一个基类A,A中的成员包含上述三种继承属性:

class A
{
    
    
public:
    int public_val = 0;
    void public_view_val();
protected:
    int protected_val = 0;
    void protected_view_val();
private:
    int private_val1 = 1;
    int private_val2 = 2;
    int private_val3 = 3;
    void private_view_val();
};

对于public_view_val()方法的定义如下:

// 类A内部的函数定义
void A::public_view_val()
{
    
    
	// 这是A的私有变量
    cout<<private_val1<<endl;
}

在main函数当中,我们创造一个A的实例a,测试能否访问a中的成员变量或函数:

    A a;
    cout<<a.public_val<<endl;
    // 外部不可访问一个类内部的protected / private 变量:
    // cout<<a.protected_val<<endl;
    // cout<<a.private_val1<<endl;

    a.public_view_val();
    // 同理, 外部不可访问一个类内部的protected / private 方法:
    // a.protected_view_val();
    // a.private_view_val();

结果发现,除了类中的public成员,其余的成员在类外部均无法访问(除非通过A中定义的public函数进行访问其私有,保护变量):

请添加图片描述

现在如果我们定义一个类B继承类A,在类B当中访问A的成员的权限上又会是如何呢?

// 类B_pubA以public继承类A
class B_pubA:public A
{
    
    
public:
    void view_A_val();
    void view_A_method();
};
void B_pubA::view_A_val()
{
    
    
    // 子类允许访问父类public,protected变量:
    cout<<public_val<<endl;
    cout<<protected_val<<endl;
    // 子类无法访问父类private变量:
    // cout<<private_val1<<endl;
}
void B_pubA::view_A_method()
{
    
    
    // 子类允许访问父类public,protected方法:
    public_view_val();
    protected_view_val();
    // 子类无法访问父类private方法:
    // private_view_val();
}

可以发现,在A的派生类B中访问A的成员又和在A外部访问稍有不同,唯一的区别就是protected成员对于类B是开放的:

请添加图片描述

请添加图片描述

现在我们就可以下结论了,假设类A内部有三种权限属性:

  1. 对于public属性,在类A的内部可以访问,在A的外部也可以访问。
  2. 对于private属性,在类A的内部可以访问,在类A的外部不可访问(除非通过public函数访问)。
  3. 对于protected属性,其访问权限仅对类A的派生类开放。其余性质和private相同。

2.继承访问权限测试(继承的权限)

当然,c++的访问权限并不仅限于类内成员,在继承上,同样具有这三种继承方式:


// 类B_pubA以public继承类A
class B_pubA:public A
{
    
    
public:
    void view_A_val();
    void view_A_method();
};
// 类B_proA以protected方法时继承类A
class B_proA:protected A
{
    
    
public:
    void view_A_val();
    void view_A_method();
};
// 类B_priA以private继承类A
class B_priA:private A
{
    
    
public:
    void view_A_val();
    void view_A_method();
};

单纯在类内部调用A的成员时,我们看不出三种继承方式下有任何区别:

请添加图片描述

但是当在外部访问派生类中的基类成员时,区别就出现了:

请添加图片描述

对于上面的现象我们可以这样理解,当派生类与何种权限继承基类时,相当于将基类的成员的最高权限全部降低到继承的等级上,比如说派生类以protected继承基类,则基类中的public方法继承后都将降低为派生类的protected。同样的,派生类以private继承基类时,基类的成员都将成为派生类的private成员(这需要和继承基类的private成员区分开)。

当然,上面的例子我们仍然看不出protected继承与private继承有任何区别,这时候我们再把继承关系延申一代,就有区别了:

定义类C以public分别继承B_priA, B_proA:

class C:public B_proA
{
    
    
public:
    void view_A();
};

//class C:public B_priA
//{
    
    
//public:
//    void view_A();
//};

对于类C的外部而言,同上面的例子相同;对于类C内部而言,继承B_proA可以访问A的pro成员,继承B_priA则A的所有成员均访问不了,原理和上面的例子相同:

请添加图片描述

请添加图片描述

我的理解是:虽然上面的实验结果看起来很绕,但是c++在继承上的权限其实和类内部定义的成员权限的原理是一致的,只不过是继承上的权限能够批量修改基类中的成员权限罢了

使用using提升成员权限

当然,在某些时候我们仍然希望一些成员拥有访问特权,比如说,我们希望在B_pri中给某个私有成员开小灶,就可以使用using声明:

// 类B_priA以private继承类A
class B_priA:private A
{
    
    
public:
    // 在子类中引用基类的成员
    // 将A的public变量在B_priA提升为public
    using A::public_val;
    void view_A_val();
    void view_A_method();
};

这时候就可以访问类B的私有成员:

请添加图片描述

当然,using无法修改派生类继承的基类中的私有属性,只能修改派生类本身成员的权限:

请添加图片描述

3.C++友元

C++中的“特权声明”不止using一个,更为常用的还有”友元“friend

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend

3.1 友元函数

值得注意的是,一个类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数

举个例子,我们定义一个类A,并声明一个外部函数为其友元函数:

class A
{
    
    
public:
    int public_val = 0;
    void public_view_val();
protected:
    int protected_val = 0;
    void protected_view_val();
private:
    int private_val1 = 1;
    int private_val2 = 2;
    int private_val3 = 3;
    void private_view_val();
    
    // 通过friend将accessA变成类A的友元函数(这个函数并不是A的成员函数)
    friend void accessA(A a);
};

这时候我们定义两个全局函数,其中一个就是A的友元函数,我们来看看函数内部对于类A的实例a的访问权限有何不同:

请添加图片描述

可见,对于一般函数,无法访问类中除public外的其余所有成员,但是在友元函数范围内,则可以访问类中的所有成员(友元的类不一定作为函数参数)。

3.2 友元类

友元类和友元函数相似,若一个类E成为另一个类A的友元类,则类C中定义的类A实例可以访问A中的所有成员:

    // 通过friend将类E变成类A的友元类
    friend class E;
class E
{
    
    
public:
    void view_A();
    void view_E_val();
};

请添加图片描述

友元类继承测试(友元的作用域)

一个友元类E能够访问允许其友元的类A的所有成员,这个我们算是清楚了,那对于A的派生类D,E还是D的友元吗??

// 定义A的派生类D
class D:public A
{
    
    
protected:
    int protected_val_d = 1;
private:
    int private_val_d = 1;
};

请添加图片描述

显然,类E依然能够访问D中继承的A的所有成员,但是却无法访问D的非公有成员,一句话概括就是“我朋友(A)的儿子(D),并不是我(E)的朋友”。

好奇宝宝的求知欲是无穷无尽的,知道了授予友元的权限无法“世袭”,现在我们还想知道一个问题,那就是友元可以“世袭”吗,比如说我们定义一个类F继承E,F还是A的友元吗??

// 定义E的派生类F
class F:public E
{
    
    
public:
    void view_A();
};

请添加图片描述

显然,F也并不是A的友元,简单一句话就是“我(E)的儿子(F),并不是我朋友(A)的朋友

总结

在本次的学习当中,我们详细了解了C++面向对象语言具有的一个很重要的特性:继承,以及继承过程中的三种访问权限public,protectedprivate

除此之外,我们还了解了其他面向语言所不具备的C++语言的特性:友元friend,详细探讨了c++友元函数以及友元类在使用过程中的一些细节。

Guess you like

Origin blog.csdn.net/SESESssss/article/details/121067099
C++