I would expect the following code to print out:
"This is a Leg", because in my Lion
class, it contains a private variable pointing to the Leg
class.
#include <iostream>
using namespace std;
class Limb{
public:
std::string getFullName() const{
auto name = getName();
return "This is a " name;
}
private:
virtual std::string getName() const{
return "Limb!";
}
};
class Leg: public Limb {
private:
std::string getName() const override{
return "Leg!"; //This is overriding the parent class's getName
}
};
class Animal{
public:
Animal():x_(){}
Limb getLimb() const{
return x_; // This should return a Leg instance when running under `Lion`, right?
}
std::string getLimbName() const{
return getLimb().getFullName();
}
private:
Limb x_;
};
class Lion: public Animal{
public:
Lion():x_(){}
private:
Leg x_; //I explicitly want a Leg instance, not an Animal.
};
int main()
{
Lion l = Lion();
std::cout<<l.getLimbName()<<std::endl;
return 0;
}
CodePudding user response:
std::cout<<l.getLimbName()<<std::endl;
This invokes this function:
std::string getLimbName() const{
return getLimb().getFullName();
}
This invokes this function:
Limb getLimb() const{
return x_;
}
This returns this object:
Limb x_;
Which is a "Limb!".
// This should return a Leg instance when running under `Lion`, right?
Nope. It is true that both Animal
and Lion
have a class member named x_
. However that does not make them one and the same. C does not work this way. They are two completely separate objects that have absolutely nothing to do, whatsoever, with each other. The one in Lion
is not involved in the above process, in any way.
Why doesn't this C child class end up running its parent's function?
Because it is not a child class, but the parent class, Limb
. It is declared as such.
CodePudding user response:
As others have pointed out, Animal::x_
is a Limb
. End of story. When an Animal
looks for its x_
member it will find a Limb
object because that's what you declared x_
to be. Unlike some other languages where a variable is implicitly a reference to some object, in C a variable is the object. Limb x
can't refer to a Leg
because it doesn't refer to anything. x
is a Limb
, and can never be anything else.
The fact that Lion
also has a different member named x_
is irrelevant. Animal::x_
and Lion::x_
are different objects with no relation to one another.
If you want a derived class to be able to change what x_
is, then you'll need to give them a way to do so. The most common approach is a pattern called dependency injection. You add a constructor to your base class that accepts a pointer to the thing you want to inject, and derived classes create an appropriate object and pass a pointer to it to the base class's constructor:
class Animal {
public:
Animal(std::unique_ptr<Limb> x) : x_{std::move(x)} {}
const Limb& getLimb() const {
return *x_;
}
std::string getLimbName() const {
return getLimb().getFullName();
}
private:
std::unique_ptr<Limb> x_;
};
class Lion : public Animal {
public:
Lion() : Animal{std::make_unique<Leg>()} {}
};
Note: With this change Limb
also needs a virtual
destructor since Leg
s will be delete
d via pointers to Limb
s.