1. 程式人生 > >C++中public、protected及private用法 以及各種繼承方式的影響 (二)

C++中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的私有變數的值(B是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;
}

執行結果如下: