我正在测试这段代码并想知道为什么在编译时没有失败?我正在使用c ++ 11和g ++ 4.7.2。
我的生产代码上有类似的结构,它在运行时给出错误,然后我发现我正在用错误的参数类型构造类。
#include <iostream>
#include <vector>
typedef std::vector<std::string> Word;
class Data {
public:
const Word &word;
Data(Word w) : word(w) {}
};
class Base{
const Data &data;
public:
Base(const Data &d): data(d) {}
~Base() {}
};
class Work : public Base{
public:
Work(const Data &d): Base(d){}
~Work() {}
};
int main(int argc, char **argv){
Word words;
words.push_back("work");
/*
* I'm confused with this constructor, why this passed the compilation
* ??
* Any special rule to reason this scenario ??
*
* But obviously it will fail at run time.
*/
const Work *work = new Work(words);
return 0;
}
答案 0 :(得分:10)
Data
可以从Word
构建,因此您可以将Word
传递给Work
构造函数。在幕后,将从传递的Data
创建Word
的实例,然后将其传递给构造函数。
您可以通过将Data
标记为Word
explicit的构造函数来避免这种情况,如下所示:
class Data {
public:
const Word &word;
explicit Data(Word w) : word(w) {}
};
这样,构造函数就不能再被隐式应用了,除非你明确地调用Work
构造函数,否则你对Data
构造函数的调用将无法编译:
const Work *work = new Work(words); // Implicit call, fails to compile.
const Work *work = new Work(Data(words)); // Explicit call, compiles.
答案 1 :(得分:5)
工作编译 * ,因为Data
有一个带Word
引用的隐式转换构造函数:
Data(Word w) : word(w) {}
这意味着你可以做一些事情,比如
Word words;
Data d1 = words;
Data d2(words);
您可以通过构造函数Work
从Data
构建Work(const Data &d): Base(d){}
:
Work w(d2);
表示以下内容也有效,因为它只涉及一个用户定义的转换:
Work w2(words); // constructs Data temporary from words, then constructs w2 with it
通过将转换构造函数声明为explicit
:
explicit Data(Word w) : word(w) {}
*您实际上没有工作,因为它涉及对临时Data
对象的悬空引用
答案 2 :(得分:2)
退出以下构造函数后,引用类型的数据成员word
将引用不再存在的对象:
class Data {
public:
const Word &word;
Data(Word w) : word(w) {}
};
创建自动存储持续时间的变量以保存w
。您将对该变量的引用存储为成员word
,然后在构造函数退出时销毁该裁判。
不管其他问题如何,我认为这不是你的意图。