但凡用過C++的人都知道:私有繼承的成員在派生類里均為私有,受保護的繼承公有和受保護的成員在派生類里為受保護。另外C++不對私有繼承和受保護的繼承的派生類指針自動轉化為基礎類。
#include <stdio.h>
struct X {int a;X():a(9) {}int sqare() {return a*a;}
};class B: X {
};class C: B {
public:
~C();
};
因為B對X私有繼承,到了類C里面不能訪問A的數據和成員函數。
C::~C()
{printf("%d **2 = %d\n",a, sqare());
}
在這里,類C的析構函數不能訪問X的數據a和成員函數sqare()。上面的代碼會被編譯器所禁止。
然而,在充分考慮了強制類型轉換手段存在的情況下,請問真的不可以嗎?
這時候,規則變的重新洗牌了。首先可以看到,在類的外面是有辦法訪問到私有繼承的數據和成員函數的:
#include <stdio.h>
struct X {int a;X():a(9) {}int sqare() {return a*a;}
};class B: X {
};class C: B {
public:
~C();
}
C::~C(){}int main()
{C a;X *p;p= (X*) &a;printf("%d **2 = %d\n",p->a, p->sqare());return 0;
}
進而想到,在C里面也這樣做,不是就可以訪問私有繼承的X中的成員了嗎,
C::~C()
{X *p;p= (X*) this;printf("%d **2 = %d\n",p->a, p->sqare());
}
不幸的是,這個代碼通不過編譯,編譯不允許在C中定義 X *p;這樣的指針,也不允許使用(X*) this;這樣的強制類型轉換。 因為私有繼承,基礎類X在孫子輩 的C中被屏蔽了。這就出現了一個奇觀,在公共區域都能訪問到的數據,到了派生類中反而訪問不到了。
回避這個問題,最好的辦法是讓B受保護繼承X,這樣就可以了。
class B:protected X {
};
然而,假設不允許改動頭文件呢?進而發現其實仍有別的辦法。就是在公共區域引進一個空類,然后在它里面聲明一個X的別名:
struct Base_Chain {
typedef struct X X;
};C::~C()
{Base_Chain::X *p;(B*&)p= (B*) this;printf("%d **2 = %d\n",p->a, p->sqare());
}
通過X的別名來引用X,騙過編譯器,這樣就可以了。
最后。為了防止過度玩弄這樣的花招,C++允許私有繼承和受保護的繼承在派生類里開放基類的權限。現在看這是非常理智的。
#include <stdio.h>
struct X {int a;X():a(9) {}int sqare() {return a*a;}
};class B: X {
public:X::a;X::sqare;
};class C: B {
public:
~C();
};
C::~C()
{printf("%d **2 = %d\n",a, sqare());
}
int main()
{C c;
}