C++从已实现的虚拟类中调用非虚拟方法

C++ Calling a non-virtual method from an implemented virtual class

本文关键字:虚拟 调用 方法 C++ 实现      更新时间:2023-10-16

我有一个接口,它也有一个普通的方法,那么我该如何调用它呢?

class Animal{
   virtual void virtualFunction()=0;
}
class Cow : Animal{
   virtual void virtualFunction(){}
   void nonVirtualFunction(){}
}
class main{
   Animal *a = new Cow();
   a->virtualFunction();
}

^:这是有效的,但当我这样做时…

a->nonVirtualFunction();

它说类Animal没有这个方法,我当然知道,但是调用该方法的最佳方式是什么

如果要调用Cow的成员函数,首先不要将其存储在多态Animal指针中:

Cow* c = new Cow();
c->nonVirtualFunction();

如果要以特定于Cow的方式使用Cow,那么将其存储在Animal*中是没有意义的。

可以使用dynamic_cast在运行时检查对象的动态类型:

Animal* a = new Cow();
if (Cow* c = dynamic_cast<Cow*>(a)) {
  c->nonVirtualFunction();
}

然而,这通常是糟糕设计的标志。

您需要使用Cow指针来调用nonVirtualFunction。Animal指针是指向具有Animal接口的奶牛的SUBSET的指针。

调用nonVirtualFunction的唯一方法是获取Cow指针。

Cow *c = dynamic_cast<Cow*>(a); 

会给你这样一个指针,假设a真的指向了一头牛。

为了更好地解释自己,我将使用真实名称来代替占位符:

class Animal{
   virtual void move()=0;
}
class Cow : Animal{
   virtual void move(){}
   void moo(){}
}
int main () {
   Animal *a = new Cow();
   a->move();
   a->moo(); // ERROR
}

当然,这是一个错误:你到底为什么要制作一个通用的Animal moo?所以问题不在于如何在任何Animal上调用moo;恰好这个调用毫无意义,编译器帮助我们注意到了这一点。

现在,Animal可能有一个非虚拟方法,可以在任何动物身上调用,而无需在子类上重写,例如:

class Animal{
   // Everything else, plus:
   std::string Name() {return name;}
private:
   std::string name;
}
int main () {
   Animal *a = new Cow();
   a->move();
   std::string animalName = a->Name(); // OK
}

正如你所看到的,如果你有一个好的设计,问题就会消失。