使用基类对象访问派生的仅类方法

时间:2018-08-20 03:43:09

标签: c++ oop inheritance polymorphism

我是OO编程的新手,我想知道如何解决以下问题-

我有以下内容:

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

    virtual functionA() = 0;
}

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

    functionA();
    functionB();
}

是否有使用基类A的对象访问functionB的方法?如果没有,为什么不可能呢?如果是,请问该如何做?我试图在此站点上找到此答案,但没有找到任何具体答案。

3 个答案:

答案 0 :(得分:1)

通常这是不可能的。类A无法访问类B中的派生方法。对于继承,一般关系是向上的。想象一下,一个C也具有functionB,其分辨率将是模棱两可的。

class A
{
}

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

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


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

话虽如此,如果实例实际上是B,则可以使用向下转换。

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

也许这就是您要达到的目标。

答案 1 :(得分:1)

我会稍微修改您的示例,以使您更好地理解:

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

    virtual Eat() = 0;
}

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

    Eat();
    Fly();
}

是否应允许Animal对象访问属于Fly的函数Bird
不,因为并非全部 AnimalBird。 但是,如果您确定某个特定的Animal对象不是Bird,则可以将Animal对象下放到Bird,然后调用Fly函数。 br /> 但是,通常不建议这样做。可以进行向上广播(将Bird广播到Animal),因为所有Bird都是Animal

答案 2 :(得分:0)

您只能使用对象A访问B的虚拟方法。这称为运行时多态性,它是通过虚拟功能实现的。因此,为了实现运行时行为,C ++编译器为每个具有虚拟功能的类或从具有虚拟功能的类继承的类插入虚拟表。

与您的代码一样,我将做一些小的修改:-

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

由于类A包含虚拟函数,因此C ++编译器会插入称为虚拟表指针的指针v_ptr。编译器还会为该类创建一个表,称为虚拟表,该表称为该类的vtable。该表在编译时创建,v_ptr保存相应类的v_table的地址。 vtable是指向虚拟函数的函数指针数组。由于functionA是纯虚函数,因此在vtable中,functionA的地址条目将为null,但是functionC在vtable中具有有效的地址条目,因为它不是纯虚函数。

虚拟表包含指向A类的functionA()和functionC函数的指针。但是由于functionA是纯虚拟的,因此实现不完整。因此,您无法创建A类的对象。

由于B类继承自A类,并且我们知道A类具有数据成员v_ptr。 B类继承了A类的v_ptr,但将为B类创建新的虚拟表。因此,B类的v_ptr持有B类的vtable的地址。由于B类已实现functionA功能。 B类的vtable包含指向B类的functionA函数的指针,但指向基类即A类的functionC函数的指针。

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