使用基类对象访问仅派生类的方法
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
?
不,因为不是所有Animal
s 是Bird
s。
但是,如果您确定特定的Animal
对象是Bird
,那么您可以将Animal
对象向下转换为Bird
,然后调用Fly
函数。
但是,通常不建议这样做。向上转换(将Bird
转换为Animal
)是可以的,因为所有Bird
s 都是Animal
s。
【讨论】:
【参考方案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#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]