1 虚函数
一个类的内存分布,虚函数表指针,普通成员变量,sizeof(A) = 为一个虚表指针(32位是4字节)+ 普通成员变量(静态什么的都不是)。虚函数本身也是函数,相当于一个指针,虚函数表里面含有虚函数,相当于一个二级指针,虚函数表指针指向虚函数表,相当于一个三级指针,所有可以通过一个三级指针直接访问某个虚函数。见代码:
#include <iostream>
using namespace std;
class A {
private:
int m_data;
public:
A(int _data = 5) : m_data(_data){
//...
}
virtual void f() {
cout << "f()" << endl;
}
virtual void g() {
cout << "g()" << endl;
}
virtual void h() {
cout << "h()" << endl;
}
~A() {
//...
}
};
void test1() {
A a; //a.m_data默认位5
//类的小大
cout << "sizeof(A) = "<<sizeof(A) << endl;
//虚表指针和一个int大小
//强行访问数据成员
int* pdata = (int*)(&a)+1;
int* pdata2 = (int*)((char*)(&a)+4);//这也行,char+4等同于int+1,都是4字节
//a的地址也是虚函数表的地址,需要向后移动4字节,强转成int*型,然后+1,
//则向后进行4个字节(所有指针都是4字节,指针类型决定其寻址大小)
cout << "a.m_data的位置 = " << (int)pdata << endl;//将地址值强转为int,方便查看
cout << "*pdata = " << *pdata << endl;
cout << "*pdata2 = " << *pdata2 << endl;
//此时打印值为5,即a.m_data的值,尽管m_data为private
//虚函数相当于一级指针(等同于普通函数)
//虚函数表相当于二级指针(通过虚函数表可以寻址虚函数,相当于虚函数的指针)
//虚函数表指针就是三级指针(虚表的指针,再加一个*)
void*** pvtable = (void***)&a;
cout << "pvtable = " << (int)&a << endl;//将地址值强转为int,方便查看
//虚表地址和a_mdata的地址相差4字节
//强行访问各个虚函数
//虚函数类型为void(*pf)()型
void(*pf1)() = (void(*)())(**((void***)&a));
//((void***)&a) 虚表指针
//*((void***)&a) 虚函数表
//**((void***)&a) 虚函数
//(void(*)()) 函数类型,类型强转
//void(*pf)() 函数指针去接住
pf1(); //调用的是f()函数
//强行访问第二个虚函数
void(*pf2)() = (void(*)())(*(*((void***)&a) + 1));
//(*((void***)&a) + 1) 虚函数表的第一个元素,类比数组
pf2(); //调用的是g()函数
void(*pf3)() = (void(*)())(*(*((void***)&a) + 2));
pf3(); //调用的是h()函数
}
int main() {
test1();
//system("pause");
return 0;
}
2 构造函数调用虚函数
直接上代码:
class Father {
private:
int m_data;
public:
Father(int _data = 1) : m_data(_data) {
func1();
}
virtual void func1() {
cout << "Father::func1() m_data = "<< m_data << endl;
}
};
class Son : public Father {
private:
int m_data;
public:
Son(int _data = 2) : m_data(_data) {
func1();
}
void func1() override {
cout << "Son::func1()" << endl;
}
};
void test2() {
Son s;
s.func1();
}
打印内容为:
Father::func1() m_data = 1
Son::func1() m_data = 2
******
Father::func1() m_data = 1
******
Son::func1() m_data = 2
子类构造之前,先调用父类构造,就m_data这个值,先找自己函数的作用域,再找其他作用域,有虚成员函数,但是没有虚成员变量之说,若有虚成员变量,猜测m_data都为2。
3 析构函数调用虚函数
class Father {
private:
int m_data;
public:
Father(int _data = 1) : m_data(_data) {
//func1(); //构造调用其他函数注释掉
}
~Father() {
func1();
}
virtual void func1() {
cout << "Father::func1() m_data = "<< m_data << endl;
}
};
class Son : public Father {
private:
int m_data;
public:
Son(int _data = 2) : m_data(_data) {
//func1(); //构造调用其他函数注释掉
}
~Son() {
func1();
}
void func1() override {
cout << "Son::func1() m_data = "<<m_data << endl;
}
};
void test3() {
Son s;
}
先析构子类,再析构父类。
4 虚函数调用虚函数
class Father {
private:
int m_data;
public:
Father(int _data = 1) : m_data(_data) {
//func1(); //构造调用其他函数注释掉
}
~Father() {
//func1();
}
virtual void func1() {
cout << "Father::func1() m_data = "<< m_data << endl;
}
virtual void func2() {
cout << "Father::func2() m_data = " << m_data << endl;
func1();
}
};
class Son : public Father {
private:
int m_data;
public:
Son(int _data = 2) : m_data(_data) {
//func1(); //构造调用其他函数注释掉
}
~Son() {
//func1();
}
void func1() override {
cout << "Son::func1() m_data = "<<m_data << endl;
}
void func2() override {
cout << "Son::func2() m_data = " << m_data << endl;
func1();
}
};
void test4() {
Son s;
s.Father::func2();
}
输出结果:
Father::func2() m_data = 1
Son::func1() m_data = 2
s.Father::func2();调用的是父类func2,而父类func2调用func1确实Son::func1(),成员函数传参的时候,默认有一个指向调用该函数的对象指针,所以Father::func2()尽管调用了,但是fun2()调用func1()时,传入参数是子类对象s,所以调用的是子类的S::func1();
转载请注明出处,谢谢