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

Accessing derived class-only methods using base class object

本文关键字:类方法 派生 访问 基类 对象      更新时间:2023-10-16

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

我有以下几点:

class A
{
public:
A() {};
~A() {};
virtual functionA() = 0;
}
class B: public A
{
public:
B() {};
~B() {};
functionA();
functionB();
}

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

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

class Animal
{
public:
A() {};
~A() {};
virtual Eat() = 0;
}
class Bird: public Animal
{
public:
B() {};
~B() {};
Eat();
Fly();
}

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

一般来说,这是不可能的。 类 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();
}

也许这就是你所追求的。

您只能使用对象 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 是指向虚函数的函数指针数组。由于函数 A 是纯虚拟的,因此在 vtable 中,函数 A 的地址条目将为空,但函数 C 在 vtable 中具有有效的地址条目,因为它不是纯虚函数。

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

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

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