0%

构造函数的问题

在工作中,遇到的几个关于构造函数的问题,以及语言边缘的坑(如何避开)。

显式类型转换函数和构造函数优先级?

1
2
3
Minimal(src);	// 不是类型转换语法吧?
// vs
(Minimal)src;

会先按照构造函数解析,还是

构造函数能不能相互调用?

http://www.cppblog.com/wolf/articles/63490.html

http://www.cnblogs.com/chio/archive/2007/10/20/931043.html

传统的 func(var) 调用方式肯定不行,因为这意味着在某构造函数中又创建了个临时对象。

但通过评论中提到的方式,还是可以复用构造函数定义的:

1
2
3
this->ClassName::ClassName() 
new (this)CLS(0);
// 经测试两种方法结果都是正确的。

补充一点,构造函数是可以调用的,但是调用方式是这样的: obj.ClassName::ClassName();
在构造函数内部调用是这样的: this->ClassName::ClassName()
楼主的调用方式是错误的,是在创建一个临时对象,不是调用构造函数

上述两篇帖子分别是 07/08 年的,在 c++11 中支持 定义构造函数时通过初始化列表的形式调用其他构造函数:

1
2
3
4
5
class Foo {
public:
Foo(char x, int y) {}
Foo(int y) : Foo('a', y) {}
};

需要指出的是,委托构造函数的语法

在委托构造函数内,成员初始值列表只有一个唯一的入口,就是类名本身。摘自《C++ Primer(5th)》P261

以下代码编译无法通过

1
2
3
4
5
6
7
8
class Foo {
public:
// 委托构造函数不能具有其他成员初始值设定项
Foo(char x, int y): Foo(y), x_(x) {}
Foo(int y) {}
private:
char x_;
};

不同的默认构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <type_traits>

struct X {
X() = default;
};

struct Y {
Y() { };
};

int main() {
static_assert(std::is_trivial<X>::value, "X should be trivial");
static_assert(std::is_pod<X>::value, "X should be POD");

static_assert(!std::is_trivial<Y>::value, "Y should not be trivial");
static_assert(!std::is_pod<Y>::value, "Y should not be POD");
}

https://stackoverflow.com/questions/20828907/the-new-keyword-default-in-c11

Giving a user-defined constructor, even though it does nothing, makes the type not an aggregate and also not trivial.

If you want your class to be an aggregate or a trivial type (or by transitivity, a POD type), then you need to use = default.

WTF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <cstdio>

class Test
{
Test() = default;
public:
void hello() const {
printf("Hello world.\n");
}
};

int main()
{
//Test acb; //error C2248: “Test::Test”: 无法访问 private 成员
Test abc{}; // THIS COMPILES
abc.hello();
return 0;
}

继承的构造函数

常用方式

1
2
3
4
5
6
class Derived
{
Derived(int a):Base(a) {}
Derived(std::string a):Base(a) {}
Derived(int a, doubel b):Base(a, b) {}
};

在 c++11 新标准中,可以简化为(是不是类似语法糖的东东?)

1
2
3
4
class Derived
{
using Base::Base; // 继承 Base 的构造函数
};

类不能继承默认、拷贝和移动构造函数。摘自《C++ Primer(5th)》P557

无效初始化

最坑的地方,在于以下代码误将成员变量 _tick_count 绑定到了临时变量,使用时其指向垃圾值。编译不报错,运行也不崩溃,无法达到预期目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct cmdlet
{
cmdlet(const std::string & label) :
label(label), _others()
{
}
cmdlet(const std::string & label, unsigned _tick_count) :
label(label), _tick_count(_tick_count) // 引用类型,覆盖掉 ① 处的初始化
{
// 并未达到预期,使得 _tick_count 作为 _other[0] 的别名
}

const std::string label;
// others
const unsigned & _tick_count = _others[0]; // ①

cmdlet(const cmdlet & rhs) : label(rhs.label), _others(rhs._others)
{

}
private:
std::array<unsigned, 3> _others;
};