--------------------------------一、“倒三角”二義性問題-------------------------------
問題描述:鹵煮之所以稱之為“倒三角問題”,是因為這一類二義性問題所處的繼承體系類似於倒三角形狀,如圖:
這樣,在子類中就存在父類A、B的兩份show(),在調用的時候就會出現二義性問題,這種問題該怎么解決呢?
面對問題:
//下面這種情況出現的二義性怎么解決?
/*
class grandpa
{
public:
void show()
{
cout<<"This is grandpa\n";
}
};
class father
{
public:
void show()
{
cout<<"This is father\n";
}
};
class son:virtual public grandpa,virtual public father
{
public:
void display()
{
cout<<"This is son\n";
}
};
int main()
{
son son;
son.show();
son.display();
cout << "Hello world!" << endl;
return 0;
}
//這里的“倒三角”問題二義性怎么解決?即有兩個基類共同派生出一個子類,這兩個基類中又同時存在相同的功能的時候
//派生出的子類在調用該功能的時候也會出現二義性問題 這時候該怎么解決?
//解決方法:利用區域限定符(::) 詳細解決方案見實驗tempt
/*
class grandpa
{
public:
void show()
{
cout<<"This is grandpa\n";
}
};
class father
{
public:
void show()
{
cout<<"This is father\n";
}
};
class son:virtual public grandpa,virtual public father
{
public:
void display()
{
cout<<"This is son\n";
}
};
int main()
{
son son;
son.show();
son.display();
cout << "Hello world!" << endl;
return 0;
}
//這里的“倒三角”問題二義性怎么解決?即有兩個基類共同派生出一個子類,這兩個基類中又同時存在相同的功能的時候
//派生出的子類在調用該功能的時候也會出現二義性問題 這時候該怎么解決?
//解決方法:利用區域限定符(::) 詳細解決方案見實驗tempt
*/
解決方法:區域限定符(::)
#include <iostream>
using namespace std;
//下面這種情況出現的二義性怎么解決?
class grandpa
{
public:
void show()
{
cout<<"This is grandpa\n";
}
};
class father
{
public:
void show()
{
cout<<"This is father\n";
}
};
class son:virtual public grandpa,virtual public father
{
public:
void display()
{
cout<<"This is son\n";
}
};
int main()
{
son son;
son.father::show();//“倒三角”問題出現的二義性利用區域限定符(::)來解決
son.grandpa::show();
son.display();
return 0;
using namespace std;
//下面這種情況出現的二義性怎么解決?
class grandpa
{
public:
void show()
{
cout<<"This is grandpa\n";
}
};
class father
{
public:
void show()
{
cout<<"This is father\n";
}
};
class son:virtual public grandpa,virtual public father
{
public:
void display()
{
cout<<"This is son\n";
}
};
int main()
{
son son;
son.father::show();//“倒三角”問題出現的二義性利用區域限定符(::)來解決
son.grandpa::show();
son.display();
return 0;
}
-------------------------------------------二、“恐怖菱形”二義性問題---------------------------------------
面對問題:
描述:有最基類A,有A的派生類B、C,又有D同時繼承B、C,那么若A中有對象a,那么在派生類B,C中就存在a,又D繼承了B,C,那么D中便同時存在B繼承A的a和C繼承A的a,那么當D的實例調用a的時候就不知道該調用B的a還是C的a,就導致了二義性。
解決方案: 虛基類、虛繼承
教科書上面對C++虛基類的描述玄而又玄,名曰“共享繼承”,名曰“各派生類的對象共享基類的的一個拷貝”,其實說白了就是解決多重多級繼承造成的二義性問題。例如有基類B,從B派生出C和D,然后類F又同時繼承了C和D,現在類F的一個對象里面包含了兩個基類B的對象,如果F訪問自己的從基類B那里繼承過來的的數據成員或者函數成員那么編譯器就不知道你指的到底是從C那里繼承過來的B對象呢還是從D那里繼承過來的B對象。
於是虛基類誕生了,將C和D的繼承方式改為虛繼承,那么F訪問自己從B那里繼承過來的成員就不會有二義性問題了,也就是將F對象里的B對象統一為一個,只有一個基類B對象,下面是一段代碼說明了對虛基類的使用。
#include <iostream>
using namespace std;
class A
{
public:
int i;
void showa(){cout<<"i="<<i<<endl;}
};
class B:virtual public A //此處采用虛繼承
{
public:
int j;
};
class C:virtual public A //此處采用虛繼承
{
public:
int k;
};
class D:public B,public C
{
public:
int m;
};
int main()
{
A a;
B b;
C c;
a.i=1;
a.showa();
b.i=2;
b.showa();
c.i=3;
c.showa();
D d;
d.i=4;
d.showa();
//cout << "Hello world!" << endl;
return 0;
}
從這個代碼我們可以看出B,C,D從A那里繼承過來了i這個變量並且它們之間不會有任何影響,如果B和C不是虛繼承方式的,那么d.i=4;就不能編譯通過了。
描述:有最基類A,有A的派生類B、C,又有D同時繼承B、C,那么若A中有對象a,那么在派生類B,C中就存在a,又D繼承了B,C,那么D中便同時存在B繼承A的a和C繼承A的a,那么當D的實例調用a的時候就不知道該調用B的a還是C的a,就導致了二義性。
圖示:

教科書上面對C++虛基類的描述玄而又玄,名曰“共享繼承”,名曰“各派生類的對象共享基類的的一個拷貝”,其實說白了就是解決多重多級繼承造成的二義性問題。例如有基類B,從B派生出C和D,然后類F又同時繼承了C和D,現在類F的一個對象里面包含了兩個基類B的對象,如果F訪問自己的從基類B那里繼承過來的的數據成員或者函數成員那么編譯器就不知道你指的到底是從C那里繼承過來的B對象呢還是從D那里繼承過來的B對象。
{
public:
int i;
void showa(){cout<<"i="<<i<<endl;}
};
{
public:
int j;
};
{
public:
int k;
};
{
public:
int m;
};
int main()
{
A a;
B b;
C c;
a.i=1;
a.showa();
b.i=2;
b.showa();
c.i=3;
c.showa();
D d;
d.i=4;
d.showa();
//cout << "Hello world!" << endl;
return 0;
}