[英]Multiple Inheritance
#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
上面的foo調用是編譯時錯誤。 我想用obj的B部分調用foo而不使用虛擬繼承。 我怎么做。
同樣,在虛擬繼承的情況下,為什么需要將偏移量信息存儲在vtable中。 這可以在編譯時自行確定。 在上述情況下,如果我們將foo與D的對象一起傳遞,則僅在編譯時才能計算D的A部分的偏移量。
對於雙重繼承,您會產生歧義-編譯器無法知道您要使用兩個A基。 如果要有兩個A底(有時可能需要這樣做),則可以通過強制轉換為B或C在它們之間進行選擇。這里默認轉換中最合適的是static_cast
(作為最弱的可用),但是它是因為您沒有轉換為派生類型,所以不需要(它確實比案例需要更強大)。 一個自定義的safe_cast
模板應該可以完成以下工作:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
同樣,在虛擬繼承的情況下,為什么需要將偏移量信息存儲在vtable中。 這可以在編譯時自行確定。 在上述情況下,如果我們將foo與D的對象一起傳遞,則僅在編譯時才能計算D的A部分的偏移量。
這是一個誤解。 現在編寫的foo函數除了是A *之外,沒有關於ptr類型的編譯類型信息,即使您傳遞B *或C *也是如此。 如果希望foo能夠根據傳遞的編譯時間進行操作,則需要使用模板:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
您的問題提到虛擬繼承。 如果要使用虛擬繼承,則需要指定:
class B: public virtual A ...
class C: public virtual A ...
使用此代碼可以編譯,但是使用此解決方案,您將無法在B :: A或C :: A(只有一個A)之間進行選擇,因此這可能與您無關。
此外,您的問題似乎混淆了兩個不同的概念:虛擬繼承(這意味着在兩個中間基類之間共享一個基類)和虛函數(這意味着允許通過基類指針調用派生類函數)。 如果希望使用A指針調用B :: eat,則可以使用虛擬函數來執行此操作,而無需進行虛擬繼承(實際上,虛擬繼承會阻止您這樣做,如上所述)。
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
如果您不接受虛擬函數,則如上所述,其編譯時機制是模板。
使用static_cast
-這里需要static_cast
繼承。
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
首先, obj
沒有名為B的成員。它從B繼承,這意味着它繼承了B的所有成員。
您可以致電:
foo(static_cast<B*>(&obj));
使它工作。
我認為static_cast不會起作用。
使用foo函數時,無論您作為參數傳遞哪種類型,編譯器都知道您有一個指向A的指針。
如果您不使用虛擬繼承,那么我認為無法從指向A的指針調用B函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.