C ++中初始化的奇怪行为

时间:2010-10-03 14:10:22

标签: c++

我有两个课程BaseDerived

class Base{
public:
    Base(int = 0);
    Base(Base&);
    Base& operator=(const Base&);
protected:
    int protectedData;
private:
    int baseData;
};

/////////////DERIVED CLASS
class Derived: public Base{
public:
    Derived(int = 0);
    Derived(Derived&);
    Derived(Base&);
    Derived& operator=(const Derived&);
private:
    int derivedData;
};

功能的实现

///////////BASE FUNCTIONS
Base::Base(int value): protectedData(value), baseData(value)
{
    cout << "base C'tor" << endl;
}


Base::Base(Base& base)
{
    baseData = base.baseData;
    protectedData = base.protectedData;
    cout << "base Copy C'tor" << endl;
}

Base& Base::operator=(const Base& base)
{
    if(this == &base) return *this;
    baseData = base.baseData;
    protectedData = base.protectedData;
    cout << "Base::operator=" << endl;
    return *this;
}

///////////DERIVED FUNCTIONS

Derived::Derived(int value): Base(value), derivedData(value)
{
    cout << "derived C'tor" << endl;
}

Derived::Derived(Derived& derived)
    : Base(derived)
{
    derivedData = derived.derivedData;
    cout << "derived Copy C'tor" << endl;
}

Derived::Derived(Base& base)
    : Base(base), derivedData(0)
{
    cout << " Derived(Base&) is called " << endl;
}

Derived& Derived::operator=(const Derived& derived)
{
    if(this == &derived) return *this;

    derivedData = derived.derivedData;
    cout << "Derived::operator=" << endl;
    return *this;
}

我的主要内容如下:

Base base(1);
Derived derived1 = base;

编译器给我一个错误:

..\main.cpp:16: error: no matching function for call to `Derived::Derived(Derived)'
..\base.h:34: note: candidates are: Derived::Derived(Base&)
..\base.h:33: note:                 Derived::Derived(Derived&)
..\base.h:32: note:                 Derived::Derived(int)
..\main.cpp:16: error:   initializing temporary from result of `Derived::Derived(Base&)'

但当我在主要内容时:

Base base(1);
Derived derived1(base);

它完美无缺。为什么呢?

EDITED

非常感谢大家,我用const检查了一切,并且一切正常,BUT我也检查了所有的电话,在这两种情况下我收到了:

base C'tor
base Copy C'tor
Derived(Base&)

我的问题是,为什么?你说我实际上打电话给: Derived(Derived(Base&))所以我必须

base C'tor
base Copy C'tor
Derived(Base&)
Derived copy c'tor //<-note, why this one is missing?

5 个答案:

答案 0 :(得分:7)

更改这些构造函数

Base(Base&);
Derived(Derived&);
Derived(Base&);

采用const引用:

Base(const Base&);
Derived(const Derived&);
Derived(const Base&);

前者不能接受临时值,后者可以。编译器想要转换

Derived derived1 = base;

Derived derived1(Derived(base));

但它不能,因为Derived(base)是一个临时值,并且没有可以获取临时Derived实例的Derived构造函数。

编辑:

请注意,由于copy elision,有时很难通过在构造函数中放置一堆cout调用来查看编译器实际执行的操作。 Copy elision允许编译器在某些情况下消除副本,即使这些副本有副作用(如打印输出)。在Wikipedia中对此进行了相当好的讨论。如果您使用的是g ++,则可以添加--no-elide-constructors开关,您将看到所有预期的副本。

此外,this answer by litb对另一个相关问题有很多关于直接初始化和复制初始化之间细微差别的详细讨论。这是很好的阅读!

答案 1 :(得分:5)

尝试通过const引用(因为它们应该)接受复制构造函数接受,然后它将起作用。 原因是:

Derived derived1 = base;

使用Derived :: Derived(Base&amp;)创建一个从基础派生的rvalue(临时对象),然后无法将其传递给Derived :: Derived(Derived&amp;),因为rvalue不能绑定到非const引用。

答案 2 :(得分:1)

解决方案很可能是在派生时添加一个指定运算符:

Derived& Derived::operator=(const Base& base);

否则编译器会尝试构建类的临时实例 - 他告诉你了!

此外,复制构造函数是MyClass(const MyClass&amp; instance),它们应该将const引用作为参数。

HTH

马里奥

答案 3 :(得分:0)

在错误的代码中,您正在执行隐式转换: 派生的衍生1 =基数;强制编译器将类'Base'的'base'对象强制转换为派生。

但是,永远不可能将基类强制转换为派生类,因为派生类可能具有基类中不存在的其他数据。反过来说,事情应该很好。重要的是要意识到在这里使用了强制转换,而不是构造函数。

代码的工作版本没有问题。它没有执行演员表演,只是调用Derived(Base&amp;);已在您的代码中定义的构造函数。

答案 4 :(得分:0)

我想我理解,它只是我的编译器的优化,没有必要创建派生对象的副本,因为它是无意义的创建