Home > OS >  Why doesn't this C child class end up running its parent's function?
Why doesn't this C child class end up running its parent's function?

Time:08-28

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>()} {}
};

Demo


Note: With this change Limb also needs a virtual destructor since Legs will be deleted via pointers to Limbs.

  •  Tags:  
  • c
  • Related