今天同事遇到一个关于拷贝构造函数的问题。代码大致如下:
class test
{
public:
test( size_t size )
{
v.assign( size, 1 );
}
test( const test& rhs)
{
v = rhs.v;
}
~test(){}
private:
vector<int> v;
};
class another
{
public:
another()
:v(7)
{
}
another( const another& rhs )
{
v = rhs.v;
}
~another(){}
private:
test v;
};
咋一看,貌似没有问题,但是gcc却编译不过去。报错如下:
在上面代码中,test类明明已经有构造函数和拷贝构造函数,为什么gcc一定要我给出一个默认构造函数出来呢?这个问题,就牵涉到了C++构造函数中的初始化列表问题了。
在编写构造函数的时候,很多人都会意思到使用初始化列表来达到避免多次构造的资源损耗,但是,在编写拷贝构造函数的时候,我们大部分时间都是这样写的。
class test
{
public:
test():a(0){.....}
test( const test& rs ){ a = rs.a; ...}
~test(){}
private:
int a;
};
而这就是造成这个问题的症结所在了。对于类而言,成员变量仅仅是声明一个变量,而真正的定义是在构造函数中做的,所以,如果在构造函数(包括拷贝构造函数)中,如果成员变量不是在初始化列表中进行初始化的话,像上面代码中的拷贝构造函数的写法,其实过程就相当于先调用一次默认构造函数对成员变量进行初始化,然后再调用=操作对成员变量进行赋值。因此,这就出现了上述gcc要求提供默认构造函数的问题了。
为了解决这个问题,我们借助初始化列表这个很好的东东,把代码改成如下,问题就不见了。
class test
{
public:
test( size_t size )
{
v.assign( size, 1 );
}
test( const test& rhs)
:v( rhs.v)
{
}
~test(){}
private:
vector<int> v;
};
class another
{
public:
another()
:v(7)
{
}
another( const another& rhs )
:v(rhs.v)
{
}
~another(){}
private:
test v;
};