鄙人愚笨,看C++2月了 對於虛函數 還是不能深刻理解,今特寫些東西,再學習一下。
程式:
#include"iostream"
using namespace std;
class A{
public:
A(int i):a(i) {cout<<"調用建構函式A "<<endl;}
void showa(){cout<<a<<"haha"<<endl;}
void showw(){cout<<"A::"<<endl;}//只有虛函數才能=0
~A(){cout<<"析構A"<<endl;};
protected:int a;
};
class B:public A//virtual public A
{
public:B(int x,int y):A(x),j(y){cout<<"調用建構函式B "<<endl;}
void showb(){cout<<a<<" "<<j<<endl;}
void showw(){cout<<"B::"<<endl;}//刪掉詞句,也能輸出C::,說明虛函數能繼承哦
~B(){cout<<"析構B"<<endl;}
protected:int j;
};
class D
{
public:D(){cout<<"構造D"<<endl;}
virtual void showd(){cout<<"d的值"<<endl;}
void showw(){cout<<"D::"<<endl;}
~D(){cout<<"析構D";}
};
class C:public B, public A,public D//virtual public A
{
public:
C(int x,int y,int z):B( x, y),A(y),k(z)
{cout<<"調用建構函式C "<<endl;}
void showc(){cout<<"B::a="<<B::a<<" "<<"A::a="<<A::a<<" "<<j<<" "<<k<<endl;}
void showw(){cout<<"C::"<<endl;}
void showd(){cout<<"CD::"<<endl;}
~C(){cout<<"析構C";}
private:int k;
};
int main()
{
C c(1,2,3);
c.showw();
return 0;
}
四個類裡面都有函數showw(),程式當然不會報錯了,因為繼承嘛。此程式的輸出是C::,說明在沒有指定域的情況下,預設的是衍生類別的函數哦!
當然有個警告: warning C4584: “C”: 基類“A”已是“B”的基類
1> f:\c++\vs2008\asd\asd\adw.cpp(5) : 參見“A”的聲明
1> f:\c++\vs2008\asd\asd\adw.cpp(15) : 參見“B”的聲明
我想:是因為A其實有兩份拷貝,也就是A-B-C和A-C。我試了下把A定義成虛基類,也就是弄成一份拷貝,警告消失。具體見注釋!
現在把基類A裡的showw()弄成虛函數。如下
#include"iostream"
using namespace std;
class A{
public:
A(int i):a(i) {cout<<"調用建構函式A "<<endl;}
void showa(){cout<<a<<"haha"<<endl;}
virtual void showw(){cout<<"A::"<<endl;}//只有虛函數才能=0
~A(){cout<<"析構A"<<endl;};
protected:int a;
};
class B:public A//virtual public A
{
public:B(int x,int y):A(x),j(y){cout<<"調用建構函式B "<<endl;}
void showb(){cout<<a<<" "<<j<<endl;}
void showw(){cout<<"B::"<<endl;}//刪掉詞句,也能輸出C::,說明虛函數能繼承哦
~B(){cout<<"析構B"<<endl;}
protected:int j;
};
class D
{
public:D(){cout<<"構造D"<<endl;}
virtual void showd(){cout<<"d的值"<<endl;}
void showw(){cout<<"D::"<<endl;}
~D(){cout<<"析構D";}
};
class C:public B, public A,public D//virtual public A
{
public:
C(int x,int y,int z):B( x, y),A(y),k(z)
{cout<<"調用建構函式C "<<endl;}
void showc(){cout<<"B::a="<<B::a<<" "<<"A::a="<<A::a<<" "<<j<<" "<<k<<endl;}
void showw(){cout<<"C::"<<endl;}
void showd(){cout<<"CD::"<<endl;}
~C(){cout<<"析構C";}
private:int k;
};
int main()
{
C c(1,2,3);
c.showw();
return 0;
}
main函數不變,輸出一模一樣,我的理解是:如果虛函數不利用衍生類別的引用或是地址,也就跟普通函數一樣了,不知道正確否,反正偵錯工具,沒發現異樣!
把主函數變下:
int main()
{
C c(1,2,3);
A *a=&c;
a->showw();
}根據結果,輸出的是C的showw(),當然很容易理解,正是虛函數的意義嘛。也可以調用a->A::showw(),輸出的就是A的showw().
再加句:a->showc();報錯,原因很簡單,此函數不是a的成員。
到此,我想大體虛函數的怎麼用可能會一點點,而其真正的意義呢?讀書求甚解。
把B類的showw()刪了,運行
結果正常跟沒刪一樣,因為B繼承了A的showw(),還是用程式說話吧。
改寫main
C c(1,2,3);
B *b=&c;
b->B::showw();//輸出A::
b->showw();//輸出C::
輸出是C的showw() 說明了B確實繼承了A 的showw() ,並且還是虛擬。虛擬函數可以繼承,實至名歸。