【问题标题】: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 接受一些参数并且只使用它们。然后呢?

标签: c++ oop inheritance polymorphism


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 1970-01-01
      相关资源
      最近更新 更多