Accessing derived class-only methods using base cl

2019-07-07 09:04发布

问题:

I am new to OO programming and I was wondering how to solve the following question -

I have the following:

class A
{
    public:
    A() {};
    ~A() {};

    virtual functionA() = 0;
}

class B: public A
{
    public:
    B() {};
    ~B() {};

    functionA();
    functionB();
}

Is there a way to access functionB using an object of the base class A? If no, why is it not possible? If yes, how does one do it? I tried to find this answer on this site but I didn't find anything concrete.

回答1:

I would modify your example slightly to give you a better understanding:

class Animal
{
    public:
    A() {};
    ~A() {};

    virtual Eat() = 0;
}

class Bird: public Animal
{
    public:
    B() {};
    ~B() {};

    Eat();
    Fly();
}

Should an Animal object be allowed to access the function Fly which belongs to Bird ?
No, because not all Animals are Birds. But if you are sure than a specific Animal object is a Bird, then you can downcast the Animal object to Bird and then call Fly function.
However, this is not generally recommended. Upcasts (casting Bird to Animal) are okay because all Birds are Animals.



回答2:

In general this is not possible. Class A can't access derived methods in Class B. The general relationship is upward for inheritance. Imagine a Class C that also has functionB, the resolution would be ambiguous.

class A
{
}

class B:public A
{
   void functionB() {};
}

class C:public A
{
   void functionB() {}
}


main()
{
  A a;
  a.functionB();  // What to call here?
}

With that being said, if an instance is in fact a B then a downcast could be used.

main()
{
  B b;
  A&a = b; // ok since a B is-a A
  auto & b1 = dynamic_cast<B&>(a);  // ok since this particular instance is-a B
  b1.functionB();
}

perhaps this is what you were reaching for.



回答3:

You can access only virtual method of B using the object A. This is called runtime-polymorphism and it is achieved with virtual function. Hence in order to implement the runtime behaviour C++ compiler inserts Virtual Table for every class having virtual function or class inherited from the class that has virtual function.

As in your code, i will make small modification:-

class A
{
    public:
    A() {};
    ~A() {};

    virtual void functionA() = 0;
    virtual void functionC();
}

class B: public A
{
    public:
    B() {};
    ~B() {};

    void functionA() override; //  C++ 11 : override keyword ensures that the function is virtual and is overriding a virtual function from a base class.
    void functionB();
}

As the class A contains a virtual function C++ compiler inserts a pointer v_ptr called as virtual table pointer. Compiler also creates a table for that class called as virtual table known as vtable for the class. The table is created compile time v_ptr holds the address of v_table of the corresponding class. vtable is a array of function pointers pointing to virtual function. As functionA is pure virtual so in vtable the address entry for functionA will be null and but functionC has a valid address entry in vtable as it is not pure virtual function.

virtual table contains pointers to functionA() and functionC function of A class. But the implementation is incomplete as functionA is pure virtual. So you can't create object of class A.

As B Class inherits from A class, and as we know A class has a data member v_ptr. B class inherits v_ptr of A class but new virtual table will be created compile time for B class. Hence v_ptr of B class holds the address of vtable of B class. As B class has implemented functionA function. vtable of B class contains pointer to functionA function of B class but pointer to functionC function of base class i.e A class.

A *a = new B();
a->functionA(); //calls B functionA
a->functionC(); //calls A functionC since we haven't overriden this function in B