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

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;
}

运行结果如下:
这里写图片描述

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

  • 子类可以访问基类的public成员、protected成员,由于子类的构造函数中没有对基类成员初始化,所以默认构造函数自动初始化。
  • public、protected、private方式继承后,成员属性的变化如下表:
基类成员属性public继承的子类成员属性protected继承的子类成员属性private继承的子类成员的属性
publicpublicprotectedprivate
protectedprotectedprotectedprivate
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源代码

  • 17
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值