继承后基类、派生类的访问属性

时间:2022-09-07 21:17:15

一、单继承与多继承

(1)一个派生类只从一个基类派生,这称为单继承(single inheritance);

(2)一个派生类有两个或多个基类的称为多重继承(multiple inheritance);(注意:区分多重继承和多级派生的概念)


二、声明派生类的方式

(1)声明派生类的一般形式为:
class 派生类名:[继承方式] 基类名
{
派生类新增加的成员
};

(2) 继承方式包括public (公用的)、private (私有的)和protected(受保护的),此项是可选的,如果不写此项,则默认为private(私有的)。


三、派生类的构成

(1)吸收基类的成员:不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收(继承方式)。

(2)改造基类成员:声明一个和某基类成员同名的新成员,该新成员将屏蔽基类同名成员。称为同名覆盖(override)

(3)发展新成员:派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。

(4)重写构造函数与析构函数。


四、派生类成员的访问属性

在讨论访问属性时,要考虑以下几种情况:
(1)、基类的成员函数访问基类成员。
(2)、派生类的成员函数访问派生类自己增加的成员。
(3)、基类的成员函数访问派生类的成员。
(4)、派生类的成员函数访问基类的成员。
(5)、在派生类外访问派生类的成员。
(6)、在派生类外访问基类的成员

对于第(1)和第(2)种情况,比较简单,基类的成员函数可以访问基类成员,派生类的成员函数可以访问派生类成员。私有数据成员只能被同一类中的成员函数访问,公用成员可以被外界访问。

第(3)种情况也比较明确,基类的成员函数只能访问基类的成员,而不能访问派生类的成员

第(5)种情况也比较明确,在派生类外可以访问派生类的公用成员,而不能访问派生类的私有成员

(4)和(6)不仅要考虑对基类成员所声明的访问属性,还要考虑派生类所声明的对基类的继承方式,根据这两个因素共同决定基类成员在派生类中的访问属性。简单来说分为以下几种:

  1. 公用继承(public inheritance)
    基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有(保持不变)。
  2. 私有继承(private inheritance)
    基类的公用成员和保护成员在派生类中成了私有成员,其私有成员仍为基类私有(全是私有)。
  3. 受保护的继承(protected inheritance)
    基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。保护成员的意思是,不能被外界引用,但可以被派生类的成员引用(五五分开)。

五、公有继承

(1)采用公用继承方式时,基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性,而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员

(2)要想访问基类的私有成员,只能通过基类的公用成员函数来引用基类的私有数据成员,即在派生类中调用基类的公有成员函数,去访问基类私有数据成员

(3)在类外定义派生类对象,可以访问基类的公有成员,其他成员不可访问

(4)总结:公有继承,派生类内能访问基类的公有,保护成员,不可访问基类私有成员,要访问它,需要通过基类的公有或保护成员函数间接访问;派生类外,派生类对象可访问基类私有成员。


六、私有继承

(1)私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。一个基类成员在基类中的访问属性和在派生类中的访问属性可能是不同的。

(2)应当注意到,虽然在派生类外不能通过派生类对象调用私有基类的公用成员函数,但可以通过派生类的成员函数调用私有基类的公用成员函数(此时它是派生类中的私有成员函数,可以被派生类的任何成员函数调用)。

(3)总结,私有继承,在派生类内,成员函数能访问基类的公有和保护成员,不可访问基类私有成员,但可以通过基类公有和保护成员函数,间接访问;派生类外,不能访问,要访问,需要在派生类内设计成员函数,该成员函数内,包含基类的成员函数,间接访问。

#include<iostream>
using namespace std;
class Base{
public:
    Base(){};
    ~Base(){};
    void print(){
        cout<<x<<","<<y<<endl;
    }
private:
    int x;
    int y;
};


class Derivation:protected Base{
public:
    Derivation(int a,int b,int c):Base(a,b),z(c){}
    ~Derivation(){}
    void print2(){
        print();//私有继承,派生类内可以访问基类的公有和保护成员函数,不能直接访问基类私有成员,需同过基类成员函数print()间接访问
        cout<<z<<endl;
    }
private:
    int z;

}

int main(){
    Derivation D(2,3,4)
    D.prin();//不能访问,需要通过设计的print2()函数间接访问
    D.print2();
}

七、保护继承

(1)保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。也就是把基类原有的公用成员也保护起来,不让类外任意访问。

(2)保护基类的所有成员在派生类中都被保护起来,类外不能访问,其公用成员和保护成员可以被其派生类的成员函数访问(私有继承都能访问,那么当然这里能访问)

(3)保护继承与私有继承的区别
直接派生类中,以上两种继承方式的作用实际上是相同的:在类外不能访问任何成员,而在派生类中可以通过成员函数访问基类中的公用成员和保护成员。但是如果继续派生,在新的派生类中,两种继承方式的作用就不同了。

如果以公用继承方式派生出一个新派生类,原来私有基类中的成员在新派生类中都成为不可访问的成员,无论在派生类内或外都不能访问,而原来保护基类中的公用成员和保护成员在新派生类中为保护成员,可以被新派生类的成员函数访问。(具体情况,见多级派生的访问属性)可参见下面代码:

#include<iostream>
using namespace std;
class Base{
public:
    Base(int a,int b){};
    ~Base(){};
    void print(){
        cout<<x<<","<<y<<endl;
    }
private:
    int x;
    int y;
};


class Derivation:private Base{
public:
    Derivation(int a,int b,int c):Base(a,b),z(c){}
    ~Derivation(){}
    void print2(){
        print();//不能直接访问基类私有成员,需同过基类成员函数print()间接访问
        cout<<z<<endl;
    }
private:
    int z;

};

class D2: public Derivation{
public:
    D2(int a,int b,int c,int d):Derivation(a,b,c),w(d){}
private:
    int w;
    void print3(){
        print();//错误,多重继承下不能访问
    }
}

假若第一次继承为保护,那么在第二次继承时,成员函数能访问print()


八、总结

  1. 大家需要记住:基类的私有成员被派生类继承(不管是私有继承、公有继承还是保护继承)后变为不可访问的成员,派生类中的一切成员均无法访问它们。如果需要在派生类中引用基类的某些成员,应当将基类的这些成员声明为protected,而不要声明为private。(声明为protected可以在类外不访问它们,具有安全性)

  2. 公用的,派生类内和派生类外都可以访问。
    受保护的,派生类内可以访问,派生类外不能访问,其下一层的派生类可以访问。
    私有的,派生类内可以访问,派生类外不能访问。
    前提条件:不可访问的,派生类内和派生类外都不能访问(即1说明的)。


九、C++类多级派生时的访问属性

在实际项目开发中,经常会有多级派生的情况。类A为基类,类B是类A 的派生类,类C是类B的派生类,则类C也是类A的派生类;类B称为类A 的直接派生类,类C称为类A的间接派生类;类A是类B的直接基类,是类 C的间接基类。

无论哪一种继承方式,在派生类中是不能访问基类的私有成员的,私有成员只能被本类的成员函数所访问,毕竟派生类与基类不是同一个类。

如果在多级派生时都采用公用继承方式,那么直到最后一级派生类都能访问基类的公用成员和保护成员。

如果采用私有继承方式,经过若干次派生之后,基类的所有的成员已经变成不可访问的了。

如果采用保护继承方式,在派生类外是无法访问派生类中的任何成员的。

而且经过多次派生后,人们很难清楚地记住哪些成员可以访问,哪些成员不能访问,很容易出错。因此,在实际中,常用的是公用继承


本文参考原文:http://c.biancheng.net/cpp/biancheng/cpp/rumen/