-1

I have a question about creating classes from an abstract class and how data gets cut.

Let's say we have an abstract class called Animal, and classes called Cat and Dog that implement said class. Both these classes implement a method from Animal called update(); however, in their update methods they access private methods and/or variables that are exclusive to themselves and not the Animal class. I understand that if we declare the classes in this manner...

Animal* dog = new Dog();
Animal* cat = new Cat();

We're only able to access methods or variables that only the Animal class specifically has; however, what if I called the update() method on each class instead, and this update method calls on the exclusive members in Cat and Dog. Would that be legal, or would this data be truncated because I created them as Animal?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Jacob Macallan
  • 959
  • 2
  • 8
  • 29

2 Answers2

3

The language does not force you to use only the polymorphic access to method 'update()'.

Example:

class Animal {
public:
   virtual void update() { std::cout << "Animal::update() " << std::endl; }
   virtual ~Animal(){}
};

class Cat : public Animal {
public:
   virtual ~Cat(){}
   virtual void update() { std::cout << "Cat::update() " << std::endl; }
};

class Dog : public Animal {
public:
   virtual ~Dog(){}
   virtual void update() { std::cout << "Dog::update() " << std::endl; }
};

int t395(void)
{
   Animal* dog = new Dog();
   Animal* cat = new Cat();

   dog->update();
   cat->update();

   dog->Animal::update();
   return (0);

}

// OUTPUT:
// Dog::update() 
// Cat::update() 
// Animal::update() 

...We're only able to access methods or variables that only the Animal class specifically has;

I agree ... dog is an Animal, and does not have a method Bark, and thus would not be able to invoke dog->bark(). But, you could add a method "virtual void talk()" to all three, and perhaps a virtual void Dog::talk() would simply invoke its local Dog::bark() method, and Cat::talk() would simply invoke it's local Cat::meow() method.

however, what if I called the update() method on each class instead, and this update method calls on the exclusive members in Cat and Dog. Would that be legal, or would this data be truncated because I created them as Animal?

Legal - yes. Data is NOT truncated (in either Animal or Dog or Cat)

a) The polymorphic dog is-a Animal, and has all methods and data attributes of Animal.

b) It also has all the methods and attributes of Dog.

Implementation is compiler specific, but one typical impl. is that the two structures (there are some complication needing compiler attention) are simply concatenated in memory. Which is first doesn't matter - its an implementation issue.

Both cat and dog instances have access to their own data and method attributes, regardless of if these method are not mapped into the polymorphic table.

Also, both cat and dog instances have access to those parts of the parent Animal instance that are public or protected (but not private).

2785528
  • 5,438
  • 2
  • 18
  • 20
  • Accessing dog->Animal::update() does not impact the derived class (in this simple example). – 2785528 Mar 07 '16 at 22:36
  • Would this truncate any data in the other classes? Would it be legal, say, that Cat calls on an exclusive member variable in its update function. Would cat->update work? – Jacob Macallan Mar 07 '16 at 22:45
  • The term 'slicing' does not apply because this inheritance is quite simple. No data is being truncated, not in the base class nor in these derived classes. – 2785528 Mar 08 '16 at 01:10
  • Imagine wanting to access (through the polymorphic pointer dog) a method "void Dog::scratchEar();" But no virtual access is planned because you decide the other animals don't have this behaviour. Some people would try casting the Animal* dog to a Dog* dog. Yuk, bad programmer. One responsible approach is to simply add "virtual Animal::scratchEar()", and "virtual Dog::scratchEar()", and also provide a "does-nothing" implementation of "Animal::scratchEar()", which will suffice for all Animals that do not implement! NO CASTING REQUIRED. Does nothing is EASY. Still polymorphic! – 2785528 Mar 08 '16 at 01:19
0

Not sure I fully understand your question, but your update() describes a virtual function call.

I suspect you are having problems understanding how inheritance and polymorphism is implemented, I know I did. Consider the following:

class base
{

private:
    int mylocalInt; //inaccessible to anyone but the base.

protected:
    int sharedInt = 5;//accessible by base, and any subtype.
public:

    base()
    {
        cout<<"creating base object"<<endl;
    }

    virtual ~base()
    {
        cout<<"Now destroying base object"<<endl;
    }

    void virtual callMe()//will be overridden, only called if you directly instantiate a base object.
    {
        cout<<"I am a base"<<endl;
    }

};

class subtypeA : public base
{
private:
    int Aint;
public:
    subtypeA()
    {
        cout<<"creating subtype"<<endl;
    }

    ~subtypeA()
    {
        cout<<"destroying subtype"<<endl;
    }

    void callMe()
    {
        cout<<"I am a subtypeA"<<endl;
    }

    int getAint()//this is a local, IE static function, a base ptr cannot access it.
    {
        return Aint;
    }

    int getSharedInt()//notice how sharedInt, located in the base object, is still accessible from within the subtype.
    {
        return sharedInt;
    }
};

int main(int argc, char* argv[] )
{
    base* ptr = new subtypeA;
    ptr->callMe();//works fine, will check which subtype, if any, ptr points to, and call the appropriate callMe(). This is because
                    //callMe() is virtual in base.
    //ptr->sharedInt//illegal, main is not part of base or a subtype of base.
    subtypeA* Aptr = (subtypeA*)ptr;//since all pointers are the same size, they can be cast to one another, is dangerous however
    cout<<Aptr->getSharedInt()<<endl;//works, getSharedInt is NOT virtual, but a normal static member of subtypeA, so in order to use it, the pointer
                                        //needs to be of type subtypeA. the sharedInt however is protected, so subtypeA can access it due to the fact that it is related to it's owner, base.

}

Now take that, and play around with it, add a subtypeB, then add subtype to that subtype, IE subtypeAA and BB for instance.

Notice that each individual class is still it's own object, distinct from any of the objects it is related to. So if a variable is private, it can't be directly accessed from the outside, just as with normal objects.

Again: There is nothing truly special about polymorphism, all it is is a nice abstraction hiding the "ugly" type-checking and so forth going on to facilitate virtual calls.

I completely forgot about your other question. No, you never have to worry about truncation in this case. In fact I asked more or less the same question some time ago, take a look: C++ subtype degeneration when placed in a container

dasblinkenlight explains it brilliantly.

Community
  • 1
  • 1
Deviatore
  • 465
  • 1
  • 4
  • 10