1. 子类继承父类的虚函数表的方式是复制一份。存在虚函数的类,都有自己的虚函数表,不与其他类共用。
2. 只要祖先类的某个函数被声明为virtual, 则在后代中无论是否显式地添加virtual,该函数一直都是虚的。
3. 如果子类重写了某个虚函数,则该类的虚函数表对应位置上的虚函数地址会被覆盖。如果完全不重写,则子类的虚函数表里面的内容和父类虚函数表内容保持一致。(需要注意的是,虽然父类的函数地址被覆盖了,但是默认的参数还是保留了,如果用父类指针去调用子类重载的函数,传的默认参数值还是父类给的默认值,只有用子类本身类型的指针去调用,才会传子类给的默认值)。
4. 虚函数表类似于类的静态成员,被该类的所有实例共享。只不过该表是只读的,不存在线程安全问题。
5. 实例对象在起始4字节中,会存放虚函数表的地址(跟系统寻址范围有关,有的系统8字节才能表示一个地址),可以通过手动寻址的方式完成虚函数调用。
6. 多重继承(有多个父类并列)时,该类有多张虚函数表,实例对象的0~3字节,表示第一个虚函数表地址,4~n字节表示第一个父类的成员变量;n+1~n+4表示第二张虚函数表地址,n+5~m表示第二个父类成员变量,以此类推(C++对象内存模型)。当这些父类又有共同祖先时,为避免数据冗余和冲突,继承方式应该是虚继承。
7. 用父类指针指向子类对象时,指针地址会根据多重继承顺序的发生相应的偏移。如A:B,C表示A同时继承了B和C,当用B*类型指向A类对象时,指针偏移0字节,当用C类型指向A类对象时,指针偏移sizeof(B)字节。用代码表示如下:
#ifdef __WIN64
typedef __int64 ADTY;
#else
typedef __int32 ADTY;
#endif
A obj;
A* a_ptr = &obj;
B* b_ptr = &obj;
C* c_ptr = &obj;
assert(((ADTY)c_ptr - (ADTY)b_ptr) == sizeof(B));
assert((ADTY)a_ptr == (ADTY)b_ptr);
8. 在构造一个对象时,对象的虚表指针指向的地址会随着构造过程发生变化。执行父类构造函数时,虚表指针指向了父类的虚表,执行子类构造函数时,虚表指针指向子类虚表。因此在构造函数中调用虚函数不会发生多态效应。
9. 析构函数不会被子类继承,在delete多态指针时,如果发现指针类型的析构函数为虚,编译器将会动用一系列复杂的机制,找到该指针真实的类型,进而调用真实的析构(该过程是静态绑定,不是运行时动态调整的)。因此,如果一个类可能会被继承,则必须将其析构函数定义为virtual。
10. 即便父类的虚函数是private的,子类的虚函数表中也依然存在它的地址,我们可以通过子类实例的首地址,寻找到虚函数表进而找到该虚函数,完成调用。同样,我们也可以通过手动寻址访问父类的私有成员变量。这样会违背c++语言的设计初衷,破坏数据的安全性,一般不要轻易使用。
#include <iostream>
#include <string>
using namespace std;
typedef void(__stdcall* Fun)();
typedef void(__stdcall* Fun1)(double);
//声明virtual,让该成员函数地址在虚函数表中留下记录
class Brass {
private:
std::string fullname;
long acctNum;
double balance;
public:
Brass(const std::string& s = "NullBody", long an = -1, double bal = 0.0);
void Deposit(double amt);
virtual void ViewAcct() const;
virtual void withdraw(double amt);
double Balance() const;
virtual void test() { cout << "Brass::test" << endl; }
virtual ~Brass() {}
};
class BrassExtra
{
public:
int vvk;
BrassExtra() :vvk(97) {}
virtual void SecondMethod()
{
cout << "BrassExtra SecondMethod" << endl;
}
};
//即便子类不再将父类的虚函数函数声明为virtual,只要祖先类中该函数是virtual,则它依然是虚函数
class BrassPlus :public Brass,public BrassExtra {
private:
double maxLoan;
double rate;
double owesBank;
public:
BrassPlus(const std::string& s = "NullBody", long an = -1,
double bal = 0.0, double ml = 500, double r = 0.11125);
BrassPlus(const Brass& ba, double ml = 500, double r = 0.11125);
void SecondMethod();
void ViewAcct()const;
void withdraw(double amt);
void ResetMax(double m) { maxLoan = m; }
void ResetRate(double r) { rate = r; }
void ResetOwes() { owesBank = 0; }
};
class BrassPlusPlus :public BrassPlus {
public:
void ViewAcct() const override { cout << "BrassPlusPlus viewacct" << endl; }
};
Brass::Brass(const std::string& s, long an, double bal) :fullname(s), acctNum(an), balance(bal) { cout << "fullname: " << fullname <<","<<"acctNum: "<< acctNum<<","<<"balance: "<< balance << endl; }
void Brass::Deposit(double amt) { return; }
void Brass::withdraw(double amt) { cout << "Brass withdraw: " << amt << endl; return; }
double Brass::Balance() const { return balance; }
void Brass::ViewAcct()const { cout << "Brass viewacct" << endl; }
BrassPlus::BrassPlus(const std::string& s, long an, double bal, double ml, double r) :Brass(s, an, bal), maxLoan(ml), rate(r) {}
BrassPlus::BrassPlus(const Brass& ba, double ml, double r) :Brass(ba), maxLoan(ml), rate(r) {}
void BrassPlus::ViewAcct()const { cout << "BrassPlus viewacct" << endl; }
void BrassPlus::withdraw(double amt) { cout << "BrassPlus withdraw: " << amt << endl; return; }
void BrassPlus::SecondMethod() { cout << "BrassPlus SecondMethod: " << endl; return; }
void test(const Brass& br) {
br.ViewAcct();
//br.withdraw(6.0);//编译不通,const 实例只能调用const成员函数;
Brass& bbp = const_cast<Brass&>(br);
bbp.withdraw(6.0);
}
int main()
{
#ifdef _WIN64
typedef __int64 ADTY;//64位操作系统,8个字节表示一个地址
#else
typedef __int32 ADTY;
#endif
cout << "Hello World!" << endl;
Brass bra("Jim", 2, 0.06);
BrassPlus brap("Jhon", 5, 0.58, 500, 0.014);
const Brass bra_2("Jack", 3, 0.02);
Brass& b1 = bra;
Brass& b2 = brap;
Brass* bas[2];
bas[0] = &bra;
bas[1] = &brap;
cout << "对象bas[0]的虚函数表位于:" << hex << *(ADTY*)bas[0] << ",对象bas[0]的第一个虚函数位于:" << hex << *((ADTY*)*(ADTY*)bas[0] + 0) << endl;
cout << "对象bas[1]的第一个虚函数表位于:" << hex << *(ADTY*)bas[1] << ",对象bas[1]的第一个虚函表的第一个虚函数位于:" << hex << *((ADTY*)*(ADTY*)bas[1] + 0) << endl;
cout << *(string*)((ADTY*)bas[1] + 1) << endl;//Brass::fullname
cout << *(long*)(((char*)((ADTY*)bas[1] + 1) + sizeof(string)) + 0) << endl;//Brass::acctNum
cout << *(double*)(((char*)((ADTY*)bas[1] + 1) + sizeof(string)) + sizeof(long) + 4) << endl;//Brass::balance
cout << "对象bas[1]的第二个虚函数表位于:" << hex << *(ADTY*)(((char*)((ADTY*)bas[1] + 1) + sizeof(string)) + sizeof(long) + 4+sizeof(double)) << endl;//+4表示内存对齐,与结构体对齐规则一致
cout << *(int*)(((char*)((ADTY*)bas[1] + 1) + sizeof(string)) + sizeof(long) + 4 + sizeof(double)+ sizeof(ADTY)) << endl;//BrassExtra::vvk
cout << "子类虚函数表会从父类继承(复制一份,不是共用一份),如果子类重写了某个虚函数,则子类的虚函数表中对应的函数地址会被覆盖" << endl;
Fun bvvv = (Fun)(*((ADTY*)*(ADTY*)(((char*)((ADTY*)bas[1] + 1) + sizeof(string)) + sizeof(long) + 4 + sizeof(double)) + 0));//对象bas[1]的第二个虚函表的第一个虚函数
bvvv();
Fun cc = (Fun)(*((ADTY*)*(ADTY*)bas[1] + 0));
Fun1 dd = (Fun1)(*((ADTY*)*(ADTY*)bas[1] + 1));
cout << "对象bas[1]虚函数调用结果:" << endl;
cc();
dd(8.9);
ADTY* ptr = (ADTY*)(&bra);
//可以看出虚函数表类似于类的静态成员,对象的首地址位置保存了虚函数表的地址
cout << "对象bra的虚函数表位于:" << hex << *ptr << ",对象bra的第一个虚函数位于:" << hex << *((ADTY*)*ptr + 0) << endl;
cout << "对象bra_2的虚函数表位于:" << hex << *(ADTY*)(&bra_2) << ",对象bra_2的第一个虚函数位于:" << hex << *((ADTY*)*(ADTY*)(&bra_2) + 0) << endl;
cout << "说明bra的虚函数表 与 bra_2的虚函数表 是同一张表" << endl;
ADTY* ptr1 = (ADTY*)*ptr;
Fun pFun = (Fun) * (ptr1 + 0); //等效于 (Fun)(*((ADTY*)*(ADTY*)(&bra)+0));
pFun();
Fun1 pFun1 = (Fun1) * (ptr1 + 1); //等效于 (Fun)(*((ADTY*)*(ADTY*)(&bra)+1));
pFun1(9.0);
cout << "Hello World end" << endl;
return 0;
}