背景
最近在编译一个库的时候发现有个编译错误,最后发现是初始化对象的时候出了问题,这里简单记录一下:
#include <iostream>
class A
{
public:
int m_a;
};
class C
{
public:
int m_c;
operator A(){};
};
class B
{
public:
B(){};
B (const A& a)
{
m_b = a.m_a;
std::cout<<"B construct"<<std::endl;
};
// B(const B& b)=delete;
int m_b;
};
int main()
{
C c;
// B b(c); //right
B b = c; //error
}
当在编译的时候出现如下报错:
尝试发现直接初始化(小括号方式)可以的,而拷贝构造却不行。
科普两个名词:
- 直接初始化(小括号)
- 拷贝初始化 (=)
- 大括号初始化 ({})
原因
经过研究发现,原来凡是用到=这个符号初始化对象的时候,候选构造函数只有
拷贝构造函数B(const B& b), 而用()去初始化对象的时候候选构造函数是所有的构造函数(本例子中也就包括B (const A& a) 和默认生成的拷贝构造函数B(const B& b))
- 当调用B (const A& a)的时候发现C可以直接转为A, 所以编译成功
- 当调用B (const B& b)的时候发现C并无法直接转为B, 所以编译失败, 做实验验证在C中加个转换函数就可以了
可以看出小括号初始化的检索的函数范围更大,所以初始化最好用小括号初始化, 不过新的c++标准建议使用{},可以覆盖()的使用场景,而且还有两个好处: - 避免内置类型的如double到int转换
- 避免A a();这种语法报错,本来是想声明一个a对象,用无参构造函数,但是编译以为你声明了一个函数,用 A a{}可以避免语法解析问题。
总结
以后要养成用大括号初始化的习惯,不然一堆坑!(这里推荐A a{1}, 而不是A a={1}, 两者还是有一些区别的,后续遇到问题再补充吧)
其他
https://www.cnblogs.com/tengzijian/p/17964231