欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++中public、protected、private继承的区别

程序员文章站 2022-06-01 11:52:35
...

public、protected、private继承的区别

写在前面

在学习C++时经常会混淆public、protected、private在继承中的概念,于是写在此博客加深理解。
首先记住以下三点:

  • 用户代码(类外)只能访问public成员变量和public成员函数。
  • 子类(继承类)能访问基类的public和protected成员(包括变量和函数),但不能访问基类的private成员(包括变量和函数),本质原因不是基类的private变量不能被继承,而是基类的private成员不能被子类直接访问。但可以通过在基类中增加一个public函数用来返回基类的private成员,再在子类用调用该public函数来访问基类的private成员。

- private成员只能被类内成员和友元friend成员访问。

一、具体实例

1.1首先,我们创建一个基类A

A.h中的代码:

#pragma once
#ifndef A_H
#define A_H
class B;//前置声明在A类的定义外!否则会编译出错
class PublicB;
class ProtectedB;
class PrivateB;
class A {
    friend PublicB;
    friend ProtectedB;
    friend PrivateB;
    friend B;
public:
    int publicValue;
    A();//编译器的默认构造函数
    A(int pbV, int ptV, int pvV);//自己声明的构造函数
    virtual ~A();//为多态基类声明virtual析构函数
    void funA();

    const int& getPrivateValue();//通过public函数返回private变量,这样在子类中就可以通过该函数访问基类的private变量了
protected:
    int protectedValue;
private:

    void setPrivateValue(int pv);//用此函数验证其他类来改变A类的私有变量
    int privateValue;
};

#endif // !A_H


A.cpp中的代码

#include "A.h"
#include<iostream>
A::A()
{
}

A::A(int pbV,int ptV, int pvV): 
    publicValue(pbV), protectedValue(ptV), privateValue(pvV)
{
}


A::~A()
{
}

void A::funA()
{
    std::cout << "publicValue = " << publicValue << std::endl;//正确,类内访问public成员
    std::cout << "protectedValue = " << protectedValue << std::endl;//正确,类内访问protected成员
    std::cout << "privateValue = " << privateValue << std::endl;//正确,类内访问private成员
}

void A::setPrivateValue(int pv) {
    privateValue = pv;
}

const int & A::getPrivateValue() {
    return privateValue;
    // TODO: 在此处插入 return 语句
}

我们可以看出,在A类中,有一个public成员变量publicValue,一个protectd成员变量protectedValue,一个private成员变量privateValue。同时,还有一个public成员函数funA,我们用此函数打印输出A类的成员变量。

1.2使用public继承方式,创建一个子类(继承类)PublicB

PublicB.h中的代码

#pragma once
#ifndef PUBLICB_H
#define PUBLICB_H

//如果要接口与实现分离,pimp方法不应该用include方法,
//应使用前置声明class A;
//这里我们只讨论public、protected、private,不讨论接口与实现分离
#include "A.h"  
#include<iostream>
//PublicB以public方式继承A
class PublicB :
    public A {
public:
    int publicValueB;//PublicB的public成员
    PublicB();
    PublicB(int pbV, int ptV, int pvV, int pbVB);
    void funB();
    ~PublicB();
};

#endif // !PUBLICB_H

PublicB.cpp中的代码

#include "PublicB.h"

PublicB::PublicB() {
}

PublicB::PublicB(int pbV, int ptV, int pvV, int pbVB) : A(pbV, ptV, pvV), publicValueB(pbVB) {}
void PublicB::funB() {
    std::cout << "publicValueB = " << publicValueB << std::endl;//正确,public成员
    std::cout << "publicValue = " << publicValue << std::endl;//正确,public继承类访问基类的public成员
    std::cout << "protectedValue = " << protectedValue << std::endl;//正确,public继承类访问基类的protected成员
    std::cout << "privateValue = " << getPrivateValue() << std::endl;//正确,继承类访问基类的public成员函数,从而访问基类的private变量部分.
    std::cout << "privateValue = " << privateValue << std::endl;//正确,继承类通过友元声明能访问基类的private成员
}

PublicB::~PublicB() {
}

我们可以看出,在PublicB类中,有两个public成员变量publicValueB、从A中继承而来的publicValue,一个protectd成员变量protectedValue,一个private成员变量privateValue(但不能再子类中访问)。同时,还有一个public成员函数funB,我们用此函数打印输出PublicB类的成员变量。

1.3使用protected方式,创建一个子类ProtectedB

ProtectedB.h中的代码

#pragma once
#ifndef PROTECTEDB_H
#define PROTECTEDB_H

#include "A.h"
#include<iostream>
class ProtectedB :
    protected A {
public:
    int publicValueB;//ProtectedB的public成员
    ProtectedB();
    ProtectedB(int pbV, int ptV, int pvV, int pbVB);
    void funB();
    ~ProtectedB();
};

#endif // !PROTECTEDB_H

ProtectedB.cpp中的代码

#include "ProtectedB.h"



ProtectedB::ProtectedB() {
}

ProtectedB::ProtectedB(int pbV, int ptV, int pvV, int pbVB) : A(pbV, ptV, pvV), publicValueB(pbVB) {
}


void ProtectedB::funB() {
    std::cout << "publicValue = " << publicValue << std::endl;//正确,基类public成员,在派生类中变成了protected,可以被派生类访问。
    std::cout << "protectedValue = " << protectedValue << std::endl;//正确,基类protected成员,在派生类中变成了protected,可以被派生类访问。
    std::cout << "privateValue = " << privateValue << std::endl;//正确,继承类通过友元声明能访问基类的private成员
    std::cout << "publicValueB = " << publicValueB << std::endl;//正确,public成员

}

ProtectedB::~ProtectedB() {
}

我们可以看出,在ProtectedB类中,有两个public成员变量publicValueB、从A中继承而来的publicValue,一个protectd成员变量protectedValue,一个private成员变量privateValue(但不能再子类中访问)。同时,还有一个public成员函数funB,我们用此函数打印输出ProtectedB类的成员变量。

1.4使用private方式,创建一个子类PrivateB

PrivateB.h中的代码

#pragma once
#ifndef PRIVATEB_H
#define PRIVATEB_H
#include "A.h"
#include<iostream>


class PrivateB :
    private A {
public:
    int publicValueB;//ProtectedB的public成员
    PrivateB(int pbV, int ptV, int pvV, int pbVB);
    void funB();
    PrivateB();
    ~PrivateB();
};

#endif // !PRIVATEB_H

PrivateB.cpp中的代码

#include "PrivateB.h"



PrivateB::PrivateB(int pbV, int ptV, int pvV, int pbVB) : A(pbV, ptV, pvV),publicValueB(pbVB){
}

void PrivateB::funB() {
    std::cout << "publicValue = " << publicValue << std::endl;//正确,基类public成员,在派生类中变成了private
    std::cout << "protectedValue = " << protectedValue << std::endl;//正确,基类protected成员,在派生类中变成了private
    std::cout << "privateValue = " << privateValue << std::endl;//正确,继承类通过友元声明能访问基类的private成员
    std::cout << "publicValueB = " << publicValueB << std::endl;//正确,public成员
    //funA();

}

PrivateB::PrivateB() {
}


PrivateB::~PrivateB() {
}

我们可以看出,在PrivateB类中,有两个public成员变量publicValueB、从A中继承而来的publicValue,一个protectd成员变量protectedValue,一个private成员变量privateValue(但不能再子类中访问)。同时,还有一个public成员函数funB,我们用此函数打印输出PrivateB类的成员变量。

1.5创建一个其他类B,用于改变A类对象的private成员并访问改变后的值

B.h中的代码

#pragma once
#ifndef B_H
#define B_H

class B {
public:
    B();
    ~B();
    void print();
};

#endif // !B_H

B.cpp的代码

#include "B.h"
#include "A.h"
#include<iostream>


B::B() {
}


B::~B() {
}

void B::print() {
    A a(1, 2, 3);
    a.setPrivateValue(5);//改变a的私有变量
    std::cout << "a.privateValue = " << a.privateValue << std::endl;//输出a的私有变量的值
}

1.6我们创建main.cpp来测试我们的类

main.cpp中的代码

#include"A.h"
#include"PublicB.h"
#include"ProtectedB.h"
#include"PrivateB.h"
#include"B.h"
#include<iostream>
int main() {
    /*一、测试A类的public、protected、private成员*/
    std::cout << "一、测试A类的public、protected、private成员" << std::endl;
    A a(1,2,3);
    a.funA();
    std::cout << "a.publicValue = " << a.publicValue << std::endl;//正确,类外用户访问A的public成员
    //std::cout << a.protectedValue << std::endl; //错误,类外用户不能访问A的protected成员
    //std::cout << a.privateValue << std::endl;//错误,类外用户不能访问A的private成员
    std::cout << "sizeof(a) = " << sizeof(a) << std::endl;
    std::cout << "------------------华丽的分割线------------------" << std::endl << std::endl;//正确,类外用户访问A的public成员

    /*二、测试PublicB类的public、protected、private成员*/
    std::cout << "二、测试PublicB类的public、protected、private成员" << std::endl;
    PublicB m_publicB(1,2,10,4);//10为PublicB类的private变量
    m_publicB.funB();//正确,类外用户访问PublicB的public成员函数
    std::cout << "m_publicB.publicValueB = " << m_publicB.publicValueB << std::endl;//正确,类外用户访问PublicB的public成员
    std::cout << "m_publicB.publicValue = " << m_publicB.publicValue << std::endl;//正确,类外用户访问PublicB继承A来的public成员,,但是值是多少呢?
    //std::cout << m_publicB.protectedValue << std::endl;//错误,类外用户不能访问PublicB继承A来的protected成员
    //std::cout << m_publicB.privateValue << std::endl;//错误,类外用户不能访问PublicB继承A来的privateValue成员
    std::cout << "sizeof(m_publicB) = " << sizeof(m_publicB) << std::endl;
    std::cout << "------------------华丽的分割线------------------" << std::endl << std::endl;

    /*三、测试ProtectedB类的public、protected、private成员*/
    std::cout << "三、测试ProtectedB类的public、protected、private成员" << std::endl;
    ProtectedB m_protectedB(1,2,11,5);//11为ProtectedB类的private变量
    m_protectedB.funB();//正确,类外用户访问ProtectedB的public成员函数
    std::cout << "m_protectedB.publicValueB = " << m_protectedB.publicValueB << std::endl;//正确,类外用户访问ProtectedB的public成员
    //这里,类外用户访问ProtectedB继承A来的public成员,但在ProtectedB类中变成了protected成员
    //std::cout << "m_protectedB.publicValue = " << m_protectedB.publicValue << std::endl;//错误,类外用户不能访问ProtectedB类的protected成员
    //std::cout << m_publicB.protectedValue << std::endl;//错误,类外用户不能访问ProtectedB继承A来的protected成员,这里变成ProtectedB类的protected成员
    //std::cout << m_publicB.privateValue << std::endl;//错误,类外用户不能访问ProtectedB继承A来的privateValue成员,这里变成ProtectedB类的protected成员
    std::cout << "sizeof(m_protectedB) = " << sizeof(m_protectedB) << std::endl;
    std::cout << "------------------华丽的分割线------------------" << std::endl << std::endl;


    /*四、测试PrivateB类的public、protected、private成员*/
    std::cout << "四、测试PrivateB类的public、protected、private成员" << std::endl;
    PrivateB m_privateB(1,2,12,6);//12为PrivateB类的private变量
    m_privateB.funB();//正确,类外用户访问ProtectedB的public成员函数
    std::cout << "m_privateB.publicValueB = " << m_privateB.publicValueB << std::endl;//正确,类外用户访问m_privateB的public成员
    //这里,类外用户访问m_privateB继承A来的public成员,但在m_privateB类中变成了private成员
    //std::cout << "m_privateB.publicValue = " << m_privateB.publicValue << std::endl;//错误,类外用户不能访问PrivateB类的private成员
    //std::cout << m_privateB.protectedValue << std::endl;//错误,类外用户不能访问PrivateB继承A来的protected成员,这里变成PrivateB类的private成员
    //std::cout << m_privateB.privateValue << std::endl;//错误,类外用户不能访问PrivateB继承A来的privateValue成员,这里变成PrivateB类的private成员
    std::cout << "sizeof(m_privateB) = " << sizeof(m_privateB) << std::endl;
    std::cout << "------------------华丽的分割线------------------" << std::endl << std::endl;

    /*五、测试B类来改变A类的private成员*/
    std::cout << "五、测试B类来改变A类的private成员" << std::endl;
    B b;
    b.print();
    system("pause");
    std::cout << "------------------华丽的分割线------------------" << std::endl << std::endl;
    return 0;
}

运行结果如下:
C++中public、protected、private继承的区别

因此,我们可以总结以下几点:

  • 子类可以访问基类的public成员、protected成员,由于子类的构造函数中没有对基类成员初始化,所以默认构造函数自动初始化。
  • public、protected、private方式继承后,成员属性的变化如下表:
基类成员属性 public继承的子类成员属性 protected继承的子类成员属性 private继承的子类成员的属性
public public protected private
protected protected protected private
private 不能继承 不能继承 不能继承

那么,问题来了?如果我们非要访问基类的private成员,该怎么实现呢?

不要慌,这里有两种方法:

  • 在基类中的public下,添加方法getPrivateValue()。如下:
public:
const int& getPrivateValue();

这里返回一个const引用:保护基类的private成员不能被修改,同时用引用是数据传递比reference-to-value更高效。

  • 使用友元。在A类中,声明PublicB、ProtectedB、PrivateB为A类的友元。如下:
class B;//前置声明在A类的定义外!否则会编译出错
class PublicB;
class ProtectedB;
class PrivateB;
class A {
    friend PublicB;
    friend ProtectedB;
    friend PrivateB;
    friend B;

    /*其他代码*/
};

github源代码

相关标签: C++ 继承