Skip to content

Instantly share code, notes, and snippets.

@shihongzhi
Created August 24, 2012 02:11
Show Gist options
  • Save shihongzhi/3444738 to your computer and use it in GitHub Desktop.
Save shihongzhi/3444738 to your computer and use it in GitHub Desktop.
在构造函数中调用虚函数
#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函数。
@shihongzhi
Copy link
Author

1.构造函数不可以是虚函数,因为虚函数时通过vtable来调用的,而vtable是通过构造函数来构建的,所以这就矛盾了,因此不可以是虚函数。
2.如果有继承存在,则多态基类的析构函数必须是虚函数,要不然对象析构的时候会导致内存没法完全释放,即没法析构子类对象的内存空间

@shihongzhi
Copy link
Author

class Widget{
public:
    Widget();                       //default构造函数
    Widget(const Widget& rhs);      //copy 构造函数
    Widget& operator=(const Widget& rhs);   //copy assignment操作符
};

Widget w1;      //调用default构造函数
Widget w2(w1);  //调用copy构造函数
w1 = w2;        //调用copy assignment操作符

@shihongzhi
Copy link
Author

Widget w3 = w2    //调用copy构造函数

对象刚定义,刚刚实例化的时候只能调用构造函数,所以不会调用copy assignment操作符。这样就可以区分 是否调用copy 构造函数 还是 copy assignment操作符
passed by value(以值传递)会调用copy构造函数,这样成本开销太大了,所以推荐用passed by reference to const(传引用)

@shihongzhi
Copy link
Author

static int number = 10; 在类中写这句话会导致这个错误:只有静态常量整型数据成员才可以在类中初始化

正确的方法:

  1. static const int number = 10; number为常量了
  2. static int number; 然后必须在类外面定义number

static成员变量是属于类的,而不是属于类对象的。所以提取static变量时是没有调用this指针的

@shihongzhi
Copy link
Author

C++默认编写并调用的函数是: default构造函数、copy构造函数、析构函数、copy assignment操作符。 唯有当这些函数被调用的时候,它们才会被编译器创建出来。

explicit用于静止隐式转换

为了实现“连续赋值”,令operator=返回一个reference to this:
Widget& operator=(const Widget& rhs)
{
......
return *this
}
此规则最好遵守,同样+=,-=,
=,/=也一样

@shihongzhi
Copy link
Author

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