文章目录
- 1.虚函数的调用过程
- 2.虚函数例题
- 例题一
- 例题二
- 例题三
- 例题四
- 例题四
1.虚函数的调用过程
从汇编上面来看:
[]代表指针解引用操作
1.op指向test对象的首地址(存放vptr),并存放在eax里面;
2.将eax所指之物(虚表的首地址)给edx
3.op所指之物给ecx(test的this指针执向了vptr),并将vptr的地址给了ecx
4.[edx+8],edx代表虚表里面的首地址add函数,+8就是指针偏移8字节,此时指向的print函数,并将print函数给eax
5.call:返回eax,此时eax里面是print函数的地址
2.虚函数例题
例题一
class Object
{
private:
int value;
public:
Object(int x=0):value(x){}
void print()
{
cout << "Object::print" << endl;
add(1);
}
virtual void add(int x)
{
cout << "Object::add" << x << endl;
}
};
class Base:public Object
{
private:
int num;
public:
Base(int x=0):Object(x+10),num(x){}
void show()
{
cout << "Base::show" << endl;
print();
}
virtual void add(int x)
{
cout << "Base::add:" << endl;
}
};
int main()
{
Base base;
base.show();
return 0;
}
运行结果:
例题二
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x)
{
cout << "Create Object:" << endl;
add(12);
}
~Object()
{
cout << "Destory Object:" << endl;
}
virtual void add(int x)
{
cout << "Object::add" << endl;
}
};
class Base :public Object
{
private:
int num;
public:
Base(int x = 0) :Object(x + 10), num(x)
{
cout << "Base Object:" << endl;
add(1);
}
~Base()
{
cout << "Destory base:" << endl;
add(2);
}
virtual void add(int x)
{
cout << "Base::add:" << endl;
}
};
int main()
{
Base base;
return 0;
}
- 构造函数是设置虚表指针
在没有调用构造函数,对象未被构建时,对象里面的属性都为随机值 - 析构函数是重置虚表指针
- 构造函数和析构函数采用静态联编,不进行查表
例题三
class Object
{
public:
virtual void func(int a = 10)
{
cout << "Object::func:a" <<a<< endl;
}
};
class Base :public Object
{
private:
virtual void func(int b = 20)
{
cout << "Base ::fun:b" << b << endl;
}
};
int main()
{
Base base;
Object* op = &base;
op->func();
return 0;
}
此题目将动态联编和静态联编发挥到了极致
例题四
class Object
{
private:
int value = 10;
public:
Object(int x = 10)
{
cout << "create object" << endl;
}
void func(int a=10)
{
cout << "func::"<<a << value << endl;
}
virtual void print()const
{
cout << "print" << endl;
}
};
int main()
{
Object obj(10);
Object* op = (Object*)malloc(sizeof(Object));
op->print();
op->func();
return 0;
}
引发了异常,原因是将对象赋值给空间,系统只负责将数据赋值,不进行虚函数指针的赋值,也就是说虚表指针仍然是随机值,解决方法一:去掉虚函数。
解决办法二:定位new
int main()
{
Object obj(10);
Object* op = (Object*)malloc(sizeof(Object));
*op = obj;
new(op)Object(obj); //通过拷贝构造对op所指针的空间构造对象
op->print();
op->func();
return 0;
}
例题四
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x)
{
cout << "Create Object:" << endl;
add(12);
}
~Object()
{
cout << "Destory Object:" << endl;
}
virtual void add(int x)
{
cout << "Object::add" << endl;
}
};
class Base :public Object
{
private:
int num;
public:
Base(int x = 0) :Object(x + 10), num(x)
{
cout << "Base Object:" << endl;
add(1);
}
~Base()
{
cout << "Destory base:" << endl;
add(2);
}
virtual void add(int x)
{
cout << "Base::add:" << endl;
}
};
int main()
{
Object* op = new Base(10);
op->add(10);
delete op;
return 0;
}
此时我们发现base并没有被析构掉,造成内存泄露,解决办法是将Object的析构函数设置为虚函数