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

Posted

技术标签:

【中文标题】使用基类对象访问仅派生类的方法【英文标题】:Accessing derived class-only methods using base class object 【发布时间】:2018-08-20 03:43:09 【问题描述】:

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

我有以下:

class A

    public:
    A() ;
    ~A() ;

    virtual functionA() = 0;


class B: public A

    public:
    B() ;
    ~B() ;

    functionA();
    functionB();

有没有办法使用基类 A 的对象来访问函数 B?如果不是,为什么不可能?如果是,如何做到这一点?我试图在这个网站上找到这个答案,但没有找到任何具体的答案。

【问题讨论】:

如果functionB 访问B 的某个成员,如果您通过A 类型的对象访问functionB,您希望程序如何工作? 请定义什么是“访问功能B”。得到它的地址,给它打电话,或者别的什么? 通过“访问函数B”,我的意思是“调用函数B” @xskxzr 如果 functionB 不访问 B 的某个成员怎么办?例如,假设 functionB 接受一些参数并且只使用它们。然后呢? 【参考方案1】:

我会稍微修改你的例子,让你更好地理解:

class Animal

    public:
    A() ;
    ~A() ;

    virtual Eat() = 0;


class Bird: public Animal

    public:
    B() ;
    ~B() ;

    Eat();
    Fly();

是否应该允许Animal对象访问属于Bird的函数Fly? 不,因为不是所有Animals 是Birds。 但是,如果您确定特定的Animal 对象是Bird,那么您可以将Animal 对象向下转换为Bird,然后调用Fly 函数。 但是,通常不建议这样做。向上转换(将Bird 转换为Animal)是可以的,因为所有Birds 都是Animals。

【讨论】:

【参考方案2】:

一般来说这是不可能的。 A类不能访问B类中的派生方法。一般关系是向上继承的。想象一个 C 类也有函数 B,分辨率会很模糊。

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

也许这就是你想要的。

【讨论】:

如果你使用dynamic_cast,你应该以一种允许你验证它是否成功的方式来做。如果使用指针进行操作,您可以检查它是否为 nullptr(不兼容的类型)。但参考,你不能,它是UB。【参考方案3】:

你只能使用对象 A 访问 B 的虚方法。这称为 runtime-polymorphism,它是通过虚函数实现的。因此,为了实现运行时行为,C++ 编译器会为每个具有虚函数的类或从具有虚函数的类继承的类插入 Virtual Table。

和你的代码一样,我会做一些小的修改:-

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 的地址条目将为空,但 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

【讨论】:

以上是关于使用基类对象访问仅派生类的方法的主要内容,如果未能解决你的问题,请参考以下文章

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

关于C++基类、派生类的引用和指针

5继承与派生2-访问控制

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

C#编程,关于基类和派生类

如果派生类作为基类返回,如何访问派生类的方法?