为什么通过引用调用会创建一个新实例?

时间:2011-09-20 13:03:35

标签: c++ qt const-reference

我通过foo调用方法const ref

// method, which is being called
void foo(const Entity & ent);

// call
Entity* e = new Entity;
foo(e);    // wrong: missing * but compiles

这段代码不仅编译,而是创建Entity的新实例,其默认值在foo范围内。我希望这不会编译或至少崩溃。

如果我正确地呼叫foofoo(*e)),一切都会被怀疑,我会在Entity内看到foo的正确值。

我正在使用Qt 4.7提供的mingw。

以下是Entity

的界面
class Entity : public QObject
{
    Q_OBJECT

public:
    Entity (QObject* parent = NULL);

    long getId() const { return this->id; }
    void setId(const long id) { this->id = id; }

    QString getName() const { return this->name; }
    void setName(const QString & name) {this->name = name; }

private:
    QString name;
    long id;
};

3 个答案:

答案 0 :(得分:15)

[已编辑]您有Entity*(通过父QObject*}到Entity的隐式转换构造函数(恰好是默认构造函数)它被用来创建一个临时实例来传入。

出于这个原因,我总是建议默认情况下使所有单参数可调用构造函数(例如,除了一个参数之外的所有参数都是默认的)显式并避免隐式转换运算符,除非它们完全执行转换语义在所有情况下都可以预期。在其他情况下,通过显式方法使转换可用。

有时隐式转换很有用,每个转换应根据具体情况进行评估。

答案 1 :(得分:2)

实际上:

Entity* e = new Entity;
foo(e); //will call: 
-> foo ( Entity(e) ) ; //will call:
-> foo ( Entity((QObject*) e );

您正在从指向实体的指针(也是指向QObject的指针)创建新的临时实体。

它编译因为它有效。

正如Mark所指出的,从Entity *到Entity的隐式转换是通过构造函数完成的,该构造函数接受类型为“指向QObject的指针”的参数。要对此进行测试,将继承更改为private,您应该收到编译错误。

为避免将来出现此类错误,请将转化构造函数声明为explicit

答案 2 :(得分:1)

您的Entity构造函数采用QObject*参数,未标记为explicit。这意味着Entity可以从Entity*隐式 构建,这是个坏消息。

此外,因为函数采用ref-to - const,所以这个隐式构造的临时可以绑定到该函数参数。

标记构造函数explicit