开发者

strange behavior of initialization in C++

开发者 https://www.devze.com 2023-01-18 08:17 出处:网络
I have two classes Base and Derived from it: class Base{ public: Base(int = 0); Base(Base&); Base& operator=(const Base&);

I have two classes Base and Derived from it:

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;
};

implementation of the functions

///////////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::operat开发者_运维知识库or=(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;
}

With the following in my main:

Base base(1);
Derived derived1 = base;

the compiler gives me an error:

..\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&)'

but when I have this in main:

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

it works perfectly. Why?

EDITED

so ok thanks for everybody, I checked it with const and all works good, BUT I check also all calls and in both cases I receive:

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

my question is, why? You said that I actually call: Derived(Derived(Base&)) so I must have

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


Change these constructors

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

To take const references:

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

The former cannot accept temporary values, the latter can. The compiler wants to convert

Derived derived1 = base;

into

Derived derived1(Derived(base));

but it can't because Derived(base) is a temporary value and there is no Derived constructor that can take a temporary Derived instance.

Edit:

Note that it is sometimes difficult to see what the compiler is actually doing by putting a bunch of cout calls in the constructors, because of copy elision. Copy elision allows the compiler in certain circumstances to eliminate copies, even if those copies have side effects (like printing output). There's a reasonably good discussion of this in Wikipedia. If you are using g++, you can add the --no-elide-constructors switch and you will see all the expected copies take place.

Also, this answer by litb to another related question has a lot of detailed discussion of the subtle differences between direct initialization and copy initialization. It's good reading!


Try making copy constructors accept by const reference (as they should), and then it'll work. Reason:

Derived derived1 = base;

creates an rvalue (temporary object) of Derived from base using Derived::Derived(Base&), which then can't be passed to Derived::Derived(Derived&) because an rvalue can't be bound to a non-const reference.


The solution will most likely be adding an assignmend operator to derived:

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

Otherwise the compiler will try to build temporary instances of classes - which he informed you about!

Also, copy constructors are MyClass( const MyClass& instance), they should take const references as arguments.

hth

Mario


In the faulty code, you are performing an implicit cast: Derived derived1 = base; forces the compiled to cast the 'base' object of class 'Base' to be casted to derived.

However, It's never possible to cast a base class to a derived class, because the derived class might have additional data that doesn't exist in the base class. The other way round, things should work fine. It's important to realize that a cast is used here, and not the constructor.

The working version of the code doesn't have the problem. It's not performing a cast, it's just calling the Derived(Base&); constructor which has been defined in your code.


I think I understood, it is just optimization of my compiler, there is no need create copy of the derived object cause it is alreary created

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号