Reputation: 7843
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;
};
///////////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;
}
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?
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?
Upvotes: 3
Views: 356
Reputation: 8374
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.
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!
Upvotes: 6
Reputation: 7843
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
Upvotes: 0
Reputation: 6869
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.
Upvotes: 4
Reputation: 5805
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.
Upvotes: 0
Reputation: 4859
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
Upvotes: 1