C++中public、protected及private用法 以及各種繼承方式的影響 (二)
阿新 • • 發佈:2019-01-23
在學習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;
}
執行結果如下: