虚函数地址的找法:
#include "stdafx.h"
#include <iostream>
using namespace std;
class CBase
{
public:
virtual void who(){cout<<"CBase"<<endl;}
};
class CDerived:public CBase
{
public:
virtual void who(){cout<<"CDerived"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
long num1=0;
long num2=0;
CBase *base=new CBase;//必须用new后,才可以找到
CDerived *derived=new CDerived;
num1=*(long*)(*(long*)base);//找到第一个虚函数的地址
num2=*(long*)(*(long*)derived);
cout<<num1<<endl;
cout<<num2<<endl;
return 0;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class CBase
{
public:
virtual void who(){cout<<"CBase"<<endl;}
};
class CDerived:public CBase
{
public:
virtual void who(){cout<<"CDerived"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
long num1=0;
long num2=0;
CBase *base=new CBase;//必须用new后,才可以找到
CDerived *derived=new CDerived;
num1=*(long*)(*(long*)base);//找到第一个虚函数的地址
num2=*(long*)(*(long*)derived);
cout<<num1<<endl;
cout<<num2<<endl;
return 0;
}
---------------------------------------
虚函数的定义要遵循以下重要规则:
1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后
联编的。
2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。
5.构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。
6.析构函数可以是虚函数,而且通常声名为虚函数。
------------------------------------
1)Derived:public Base
CBase pBase;
CDerived pDerived;
CBase *pBase2= new CDerived;
delete pBase2;
CDerived pDerived2;
//results:
//CBase::CBase // CBase pBase;
//CBase::CBase //CDerived pDerived;
//CDerived:: CDerived
//CBase::CBase //CBase *pBase2= new CDerived;
//CDerived:: CDerived
//CBase::~CBase // delete pBase2;//因为基类的析构不是虚,如 是则先调用子类的析构
//CBase::CBase //CDerived pDerived2;
//CDerived:: CDerived
//CDerived::~CDerived //CDerived pDerived2;
//CBase::~CBase
//CDerived::~CDerived //CDerived pDerived;
//CBase::~CBase
//CBase::~CBase //CBase pBase;
//Press any key to continue
如果是子类构造先基类,再子类
如果是子类析构先子类,再基类
但如果基类析构不是虚,则CBase *pBase2= new CDerived;
delete pBase2;只调用基类.否则如果基类析构是虚,则先调用子类,再调用基类。
如果是用new初始化的,必须用delete来释放,否则不调用析构函数。
CDerived pDerived(10);//the base class must be have the defaut constructor
//CBase::CBase
//this is defuat constructor function
//CDerived:: CDerived
//CDerived::~CDerived
//CBase::~CBase
//CBase::~CBase
//Press any key to continue
如果子类中有基类的对象成员,则先调用基类的构造函数,再调用基类的构造函数对基类的对象成员初始化,最后才调用子类的构造函数,析构正好顺序相反。
2)CBase1:public CBase
CBase2:public CBase
CDervied:public CBase1,CBase2
CDerived pdereved;
如果没有定义为虚继承 ,先调用基类再子类然后再基类再子类最后才调用子子类构造。
CBase::CBase()!
CBase1::CBase()!
CBase::CBase()!
CBase2::CBase()!
CDerived::CDerived()!
CDerived::~CDerived()!
CBase2::~CBase()!
CBase::~CBase()!
CBase1::~CBase()!
CBase::~CBase()!
Press any key to continue
如果cbase1与cbase2是虚继承cbase,则只调用一次基类
CBase::CBase()!
CBase1::CBase()!
CBase2::CBase()!
CDerived::CDerived()!
CDerived::~CDerived()!
CBase2::~CBase()!
CBase1::~CBase()!
CBase::~CBase()!
Press any key to continue
-----------------------------------
多重继承的成员调用:
cbase
CBase1:public CBase
CBase2:public CBase
CDervied:public CBase1,CBase2
1)当cbase1与cbase2不是虚继承的时:dervied不能访问基类继承而来(即共有的)的任何成员,不能识别。
2)当cbase1与cbase2是虚继承的时,dervied可以访问cbase中没有1和2重新定义的成员,也能访问只被1或只被2重新定义的成员,这是调用1或2中的成员,当dervied中有重写时,调用derived中重新定义的成员。(共有)
:保证我们在不考虑继承而来的隐藏成员时,能够识别该调用那个类中的!则编译器也能识别!
3)
在调用变量的时候,要指出时属于那个类。