派生類成員對基類的訪問
作用域分辨符:
就是::用來限定要訪問的成員所在的類的名稱;
表示式是:
基類名::成員名; //資料成員
基類名::成員名(引數表)//成員函式
加入作用域分辨符可以防止同名覆蓋,也可以保證訪問不出現二義性;(避免二義性,記憶體中只有一份拷貝,用到虛基類)
例子:
class B1
{
public:
int nV;
void fun()
{
cout<<"member of B1"<<endl;
}
};
class B2
{
public:
int nV;
void fun()
{
cout<<"Member of B2"<<endl;
}
};
class C1:public B1,public B2
{
public:
int nV;
void fun()
{
cout<<"member of C1"<<endl;
}
};
void main()
{
C1 c1;
c1.nV = 1;
c1.fun();
c1.B1::nV = 10;
cout<<c1.B1::nV<<endl;
c1.B1::fun();
c1.B2::fun();
}
下面的語句就是作用域訪問,說明訪問的是類B1和類B2的函式fun()
c1.B1::fun();
c1.B2::fun();
如果沒有這樣的作用域名,直接呼叫fun(),就會訪問派生類中的fun(),造成同名覆蓋;
注意:如果派生類中沒有宣告同名的函式fun(),則直接通過c1.fun()的方式呼叫函式會出錯,不知道是誰的fun(),(有可能是B1的或者是B2的)這就是二義性;
虛基類:
class B1
{
public:
int nV;
void fun()
{
cout<<"member of B1"<<endl;
}
};
class B2
{
public:
int nV;
void fun()
{
cout<<"Member of B2"<<endl;
}
};
class C1:virtual public B1//, virtual public B2
{
public:
int nV;
// void fun()
// {
// cout<<"member of C1"<<endl;
// }
};
void main()
{
C1 c1;
c1.nV = 1;
c1.fun();
c1.B1::nV = 10;
cout<<c1.B1::nV<<endl;
c1.B1::fun();
/* c1.B2::fun();*/
}
把上面的程式碼改動一下,就是下面的結果:
member of B1
10
member of B1
Press any key to continue
這時候呼叫基類B1的時候採用虛基類的繼承方法,這時候從不同路徑繼承過來的同名函式成員在記憶體中就只有一個拷貝,同一個函式名也只有一個對映,這樣也就解決了同名函式的
唯一標示問題。
此時派生類中就不用在定義同名函數了,否則又要同名覆蓋;
虛基類中也可以穿插作用域分類法;作用域訪問仍起作用;
上面的例子是一個派生類繼承一個基類,虛基類一般都是一繼承一或者多繼承一,不能一繼承多,不然可能會造成多義性,特別是兩個基類中有同名函式的時候;
兩個基類函式沒有同名函式的時候,通過虛基類繼承過來派生類可以實現一繼承多;
例子:
class B1
{
public:
int nV;
void fun()
{
cout<<"member of B1"<<endl;
}
};
class B2
{
public:
int nV;
void fun2()
{
cout<<"Member of B2"<<endl;
}
};
class C1:virtual public B1, virtual public B2
{
public:
int nV;
void fun1()
{
cout<<"member of C1"<<endl;
}
};
void main()
{
C1 c1;
c1.nV = 1;
c1.fun1();
c1.B1::nV = 10;
cout<<c1.B1::nV<<endl;
c1.fun();
c1.fun2();
}
結果是:
member of C1 //呼叫自己的函式成員
10
member of B1 //呼叫B1類的成員函式(虛基類的方式繼承)
Member of B2 //呼叫B2類的成員函式(虛基類的方式繼承)
Press any key to continue