㈠ c++有趣現象:private的成員函數可以在類的外部調用
發現新大陸了呵呵,不錯,但是,它並不是C++的缺陷或是被設計者所忽視的問題。
當我們使用虛函數的時候,它的訪問規則是在聲明的時候被確定的,而不是在被「子類重寫」(overridden)的時候,虛函數的訪問規則不會受到來自被重寫的子類函數的影響,更進一步說,當某個對象A的引用B(特指間接訪問)用來調用該對象的虛函數時,對於該對象A的一切聲明信息,都取決於該對象的引用B,而不是這個引用所引用的對象A。
C++標准里有對該問題的具體說明:當一個子類函數通過基類的指針調用時,訪問許可權取決於基類對該函數的聲明。
參考C++ Standard ISO/IEC 14882:2003(E) 第11.6節:
11.6 Access to virtual functions [class.access.virt]
The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); //OK: B::f() is public,
// D::f() is invoked
pd->f(); //error: D::f() is private
}
—end example]
Access is checked at the call point using the type of the expression used to denote the object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.
至少我們在程序編譯時無法獲知這個指針的值,它會指向何種位置。
經驗:private僅僅是一個訪問限定符,它只限定函數和數據不能被「直接」訪問,而不擔保這些函數和數據會被通過其他方法間接地訪問到,在成員函數中返回一個類私有數據成員的引用也是這個道理。
另外,如果不是特殊的需要,一般來說,這並不是一個好的設計,有點自找麻煩的味道!
㈡ 子類里覆蓋父類虛函數的後的成員函數,能不能訪問父類私有成員,,,,
私有成員是不能被子類訪問,無論是子類中的什麼函數。
public就是外面能訪問,
private就是外面不能訪問。
這是訪問控制的。
㈢ C++純虛函數有受保護的虛函數a和私有成員變數,其子類實現了a函數,a如何訪問基類的私有成員變數
除非基類為子類再提供非私有的getter/setter或者把子類聲明為友元類或者直接改為非私有成員變數, 否則無法訪問
㈣ c++ 如何訪問抽象類的私有成員
根據別人的回答和你的追問,我發現了問題所在。
你的題目要求是數據成員定義的為私有,而不是成員函數定義為私有啊~~
數據成員和成員函數是不一樣的啊。
若數據成員為私有,定義一個公有成員函數T getMember() const{return member;}就可以讓別人獲得這個私有數據成員啦。
總之你的成員函數要定義為公有的。除非是你的類自己用的間接函數(僅僅被類的其他成員函數調用)。否則定義為私有,其他對象不能訪問,就沒有意義了
㈤ C++中,基類的虛函數的訪問許可權是private時,它的派生類對虛函數的訪問許可權到底是怎樣的
B *bp指針時,只能按照類B的介面規則來訪問,你在D1裡面更改了訪問許可權,父類是無法知曉子類的更改的,你這個做法叫做隱藏了介面。一般的代碼編寫中很少使用你這個做法。
B類的b方法是private的,所以main函數無權訪問。
D1類的a方法覆蓋了父類的方法a,許可權已經更改為private,所以main無法直接使用D1的實例來訪問a方法。
這些都是語法層面的東西而已。
還有一點,這種隨心所欲的代碼風格設計在工作中是需要避免的。
回到這個問題:
基類的虛函數的訪問許可權是private時,它的派生類對虛函數的訪問許可權到底是怎樣?
答案:子類無法派生和繼承父類的private成員和方法。父類的private只屬於父類所有,只有父類和父類的友元才能訪問父類的private成員和方法。
㈥ C++ 虛函數使用以及繼承的問題 急~
#include <iostream>
#define PI 3.14
using namespace std;
class container
{
public:
container(int radius=0){
this->radius = radius;/*賦值給類的成員變數*/
}
virtual void Square()=0;
virtual void Volume()=0;
int GetRadius(){return radius;} /*給私有成員變數提供一個訪問的函數*/
/*要想修改就提供一個void SetRadius(int radius)的函數*/
private:
int radius;
};
class cube:public container
{
public:
cube(int radius1):container(radius1){}
virtual void Square()
{
/*基類的私有成員在這里無法之間反問,可通過基類的成員函數訪問,下面凡事訪問radius都通過
GetRadius()來訪問*/
square1=4*PI*GetRadius()*GetRadius();
cout<<"the cube's square is:"<<square1<<endl;
}
virtual void Volume()
{
volume1=(4.0/3)*PI*GetRadius()*GetRadius()*GetRadius();/*4/3等於1了,要寫成4.0/3才對 */
cout<<"the cube's volume is:"<<volume1<<endl; /*這里應該是volume1*/
}
private:
double square1,volume1;
};
class sphere:public container
{
public:
sphere(int radius1):container(radius1){}
virtual void Square()
{
square2=6*GetRadius()*GetRadius();
cout<<"the sphere's square is:"<<square2<<endl;
}
virtual void Volume()
{
volume2=GetRadius()*GetRadius()*GetRadius();
cout<<"the sphere's volume is:"<<volume2<<endl;
}
private:
double square2,volume2;
};
class cylinder:public container
{
public:
cylinder(int radius1):container(radius1){}
virtual void Square()
{
cout<<"please input the cylinder's height=";
cin>>height;
square3=2*PI*GetRadius()*GetRadius()+2*PI*GetRadius()*height;
cout<<"the cylinder's square is:"<<square3<<endl;
}
virtual void Volume()
{
volume3=PI*GetRadius()*GetRadius()*height;
cout<<"the cylinder's volume is:"<<volume3<<endl;
}
private:
double square3,volume3;
int height;
};
int main()
{
//container container1;
int a;
cout<<"Please input a radius=";
cin>>a;
cube cube1(a);
sphere sphere1(a);
cylinder cylinder1(a);
cube1.Volume();
cube1.Square();
sphere1.Volume();
sphere1.Square();
cylinder1.Square();
cylinder1.Volume();
return 0;
}
㈦ 高分 c++ typedef 訪問基類的私有虛函數
//使用typedef來定義一個函數指針,可以參閱相關資料
typedefvoid(*Fun)(void);
voidmain()
{
Bb;//一個子類的對象
//這里如果不用typedef的話就應該是
//void(*pFun)(void);
FunpFun;
for(inti=0;i<3;i++)
{
//其實是得到b的地址,但是不能直接寫成intaddr=&b;這樣編譯器會報錯的
//所以才有了下面的兩個*
intaddr=*(int*)&b;
//現在addr變成了存儲b開始的地址的一個int型變數,所以我們還需要:
//classB的布局為:B的vtable,函數h的地址
//而B的vtable展開就是:函數g的地址,函數f的地址
//所以B的布局展開就是:函數g(被B覆寫)的地址,函數f(A的f)的地址,函數h的地址
//每個地址佔4個位元組
//那麼b+0為g的地址,b+4為f的地址,b+8為h的地址
//但是為什麼循環里是按照1遞增呢?因為上面的情況是按照char類型遞增的
//根據C的定址規則,增加一個int其實就是增加了4個位元組
//所以我們有了(int*)addr,這是說按照int型的字長來增加定址位元組數
//經過上面的分析,可以知道:
//((int*)*(int*)(&b)+0)其實就是g的地址
//((int*)*(int*)(&b)+1)其實就是f的地址
//((int*)*(int*)(&b)+2)其實就是h的地址
//那麼它終究還是一個地址,於是前面再加了一個*,就是函數的內容
pFun=(Fun)*((int*)*(int*)(&b)+i);
//然後開始運行這個函數
pFun();
}
}
vtable很復雜,可以參看C++對象模型那本書,如果只是想現在大致了解一下,可以參看下面的網址
http://blog.csdn.net/haoel/article/details/1948051/
我講的也可能不對,不可盡信。