Created
August 24, 2012 02:11
-
-
Save shihongzhi/3444738 to your computer and use it in GitHub Desktop.
在构造函数中调用虚函数
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
using namespace std; | |
class C180 | |
{ | |
public: | |
C180() { | |
foo(); | |
this->foo(); | |
} | |
virtual void foo() { | |
//*this == *(void**)this | |
cout << "<< C180.foo this: " << this << " vtadr: " << *(void**)this << endl; | |
} | |
}; | |
class C190 : public C180 | |
{ | |
public: | |
C190() {} | |
virtual void foo() { | |
cout << "<< C190.foo this: " << this << " vtadr: " << *(void**)this << endl; | |
} | |
}; | |
int _tmain(int argc, _TCHAR* argv[]) | |
{ | |
C190 obj; | |
//output: | |
//<< C180.foo this: " << this << " vtadr: " << *(void**)this | |
//<< C180.foo this: " << this << " vtadr: " << *(void**)this | |
obj.foo(); | |
//output: | |
//"<< C190.foo this: " << this << " vtadr: " << *(void**)this | |
getchar(); | |
return 0; | |
} | |
//标准中提到:这是一种特例,在这种情况下,即在构造子类时调用父类的构造函数,而父类的构造函数中又调用了虚成员函数,这个虚成员函数即使被子类重写,也不允许发生多态的行为。 | |
//因为这种情况下的实例化子类对象是,会先调用父类的构造函数, | |
//然后父类构造函数申请相应对象的内存空间,得到指向这段内存空间的this指针,同时构建vtable,用vtable point指向刚刚建立的vtable,vtable中写了虚函数C180:foo的指针。 | |
//然后在调用子类的构造函数,因为重载了foo虚函数,所以用指向C190:foo的指针覆盖vtable中虚函数C180:foo的指针, 这样就实现了多态。 | |
//而在父类构造函数中调用虚函数foo时,那是vtable中还是保存着虚函数C180:foo的指针,所以调用的是C180:foo函数。 |
Author
shihongzhi
commented
Aug 24, 2012
Widget w3 = w2 //调用copy构造函数
对象刚定义,刚刚实例化的时候只能调用构造函数,所以不会调用copy assignment操作符。这样就可以区分 是否调用copy 构造函数 还是 copy assignment操作符
passed by value(以值传递)会调用copy构造函数,这样成本开销太大了,所以推荐用passed by reference to const(传引用)
static int number = 10; 在类中写这句话会导致这个错误:只有静态常量整型数据成员才可以在类中初始化
正确的方法:
- static const int number = 10; number为常量了
- static int number; 然后必须在类外面定义number
static成员变量是属于类的,而不是属于类对象的。所以提取static变量时是没有调用this指针的
C++默认编写并调用的函数是: default构造函数、copy构造函数、析构函数、copy assignment操作符。 唯有当这些函数被调用的时候,它们才会被编译器创建出来。
explicit用于静止隐式转换
为了实现“连续赋值”,令operator=返回一个reference to this:
Widget& operator=(const Widget& rhs)
{
......
return *this
}
此规则最好遵守,同样+=,-=,=,/=也一样
class Bitmap {...};
class Widget{
private:
Bitmap* pb;
}
//自我赋值不安全,并且异常也不安全
Widget& Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb)
return *this;
}
//自我赋值安全,异常不安全
Widget& Widget::operator=(const Widget& rhs)
{
if(this == &rhs) return *this;
delete pb;
pb = new BItmap(*rhs.pb);
return *this;
}
//自我赋值安全,并且异常安全
//可以加上这句判断 if(this == &rhs) return *this;
//这个就看情况了,如果自我赋值特别多的话,这句判断语句可以加上。
//如果不多的话,则应该不加,因为这句判断也是需要空间的,并且不加的情况下,自我赋值也是安全的
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap* pOrig = pb;
pb = new BItmap(*rhs.pb);
delete pOrig;
return *this;
}
//copy and swap技术
class Widget{
void swap(Widget& rhs); //交换*this和rhs的数据
}
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment