为什么是“虚拟”?对于派生类中的重写方法是可选的吗?

发布于 2024-09-03 14:56:37 字数 629 浏览 10 评论 0原文

当一个方法在类中被声明为virtual时,其在派生类中的重写也自动被视为virtual,并且C++语言使该关键字virtual code> 在这种情况下是可选的:

class Base {
    virtual void f();
};
class Derived : public Base {
    void f(); // 'virtual' is optional but implied.
};

我的问题是:使 virtual 成为可选的理由是什么?

我知道编译器并不是绝对有必要被告知这一点,但我认为如果编译器强制执行这样的约束,开发人员将会受益。

例如,有时当我阅读其他人的代码时,我想知道一个方法是否是虚拟的,我必须追踪它的超类来确定这一点。一些编码标准 (Google) 实现了这一点“必须”将 virtual 关键字放入所有子类中。

When a method is declared as virtual in a class, its overrides in derived classes are automatically considered virtual as well, and the C++ language makes this keyword virtual optional in this case:

class Base {
    virtual void f();
};
class Derived : public Base {
    void f(); // 'virtual' is optional but implied.
};

My question is: What is the rationale for making virtual optional?

I know that it is not absolutely necessary for the compiler to be told that, but I would think that developers would benefit if such a constraint was enforced by the compiler.

E.g., sometimes when I read others' code I wonder if a method is virtual and I have to track down its superclasses to determine that. And some coding standards (Google) make it a 'must' to put the virtual keyword in all subclasses.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橘寄 2024-09-10 14:56:37

是的,在这种情况下让编译器强制执行虚拟确实会更好,而且我同意这是为了向后兼容性而维护的设计错误。

然而,如果没有它,有一个技巧是不可能的:

class NonVirtualBase {
  void func() {};
};

class VirtualBase {
  virtual void func() = 0;
};

template<typename VirtualChoice>
class CompileTimeVirtualityChoice : public VirtualChoice {
  void func() {}
};

有了上面的内容,我们就可以在编译时选择是否需要 func 的虚拟性:

CompileTimeVirtualityChoice<VirtualBase> -- func is virtual
CompileTimeVirtualityChoice<NonVirtualBase> -- func is not virtual

...但同意,对于寻求函数虚拟性的成本来说,这只是一个小小的好处,而我自己,我总是尝试在任何适用的地方输入 virtual 。

Yeah, it would really be nicer to make the compiler enforce the virtual in this case, and I agree that this is a error in design that is maintained for backwards compatibility.

However there's one trick that would be impossible without it:

class NonVirtualBase {
  void func() {};
};

class VirtualBase {
  virtual void func() = 0;
};

template<typename VirtualChoice>
class CompileTimeVirtualityChoice : public VirtualChoice {
  void func() {}
};

With the above we have compile time choice wether we want virtuality of func or not:

CompileTimeVirtualityChoice<VirtualBase> -- func is virtual
CompileTimeVirtualityChoice<NonVirtualBase> -- func is not virtual

... but agreed, it's a minor benefit for the cost of seeking a function's virtuality, and myself, I always try to type virtual everywhere where applicable.

爱殇璃 2024-09-10 14:56:37

作为相关说明,在 C++0x 中,您可以选择通过新的属性语法强制执行显式覆盖。

struct Base {
  virtual void Virtual();
  void NonVirtual();
};

struct Derived [[base_check]] : Base {
  //void Virtual(); //Error; didn't specify that you were overriding
  void Virtual [[override]](); //Not an error
  //void NonVirtual [[override]](); //Error; not virtual in Base
  //virtual void SomeRandomFunction [[override]](); //Error, doesn't exist in Base
};

您还可以通过 [[hiding]] 属性指定何时隐藏成员。它使您的代码变得更加冗长,但它可以在编译时捕获许多恼人的错误,就像您使用 void Vritual() 而不是 void Virtual() 并且当您打算覆盖现有函数时,最终引入了一个全新的函数。

As a related note, in C++0x you have the option of enforcing being explicit with your overrides via the new attribute syntax.

struct Base {
  virtual void Virtual();
  void NonVirtual();
};

struct Derived [[base_check]] : Base {
  //void Virtual(); //Error; didn't specify that you were overriding
  void Virtual [[override]](); //Not an error
  //void NonVirtual [[override]](); //Error; not virtual in Base
  //virtual void SomeRandomFunction [[override]](); //Error, doesn't exist in Base
};

You can also specify when you intend to hide a member via the [[hiding]] attribute. It makes your code somewhat more verbose, but it can catch a lot of annoying bugs at compile time, like if you did void Vritual() instead of void Virtual() and ended up introducing a whole new function when you meant to override an existing one.

故事↓在人 2024-09-10 14:56:37

设计上的弱点,我同意。
我还认为,如果两个不同的事情有不同的语法,那就太好了:

  1. 声明虚拟函数。即派生类中可能被重写的函数。 (这个东西实际上在vtable中添加了一个新的函数条目。)
  2. 重写派生类中的虚拟函数。

根据当前的 C++ 规则,当重写函数时,很容易搞砸事情。如果您输入了错误的函数名称(或者在其参数列表中犯了错误),那么您实际上会执行 (1) 而不是 (2)。

并且您没有错误/警告。只需在运行时获得惊喜即可。

Weak point in design, I agree.
I also think that'd be really nice if there was a different syntax for two different things:

  1. Declaring a virtual function. I.e. the function that may be overridden in derived class. (This thing actually adds a new function entry in the vtable.)
  2. Overriding a virtual function in the derived class.

With current C++ rules when overriding a function - it's easy to screw things. If you mistype the function name (or make a mistake in its parameters list) - then you actually do (1) instead of (2).

And you have no error/warning. Just get the surprise at run-time.

独守阴晴ぅ圆缺 2024-09-10 14:56:37

由于该语言无法强制执行“良好”风格,因此 C++ 通常甚至不会尝试。至少在我看来,在任何情况下,包含这样的冗余说明符是否是一种好的风格还有待商榷(就我个人而言,我讨厌它们在那里)。

Google 的(至少部分)编码标准在某些情况下可能有意义,但就 C++ 的总体情况而言,通常最多被认为是平庸的建议。在某种程度上,他们甚至承认——他们公开声明的其中一些只是为了适应他们的旧代码。其他部分他们不那么直接承认,并且(完全诚实地)该论点无论如何都不会支持他们的某些标准(即其中一些似乎缺乏真正的理由)。

Since the language can't enforce "good" style, C++ generally doesn't even try. At least IMO, it's open to question whether including redundant specifiers like this is good style in any case (personally, I hate when they're there).

(At least parts of) Google's coding standards may make sense under some circumstances, but as far as C++ in general goes, are generally considered mediocre advice at best. To an extent, they even admit that -- some of them they openly state are only really there to fit with their old code. Other parts they don't admit so directly, and (to be entirely honest) that argument wouldn't support some of their standards anyway (i.e., some of it seems to lack real justification).

放低过去 2024-09-10 14:56:37

这是一个很好的问题,而且我当然同意,如果某个方法已在基类中声明为 virtual,则在派生类中重新声明该方法是一种很好的风格。虽然有些语言将风格融入到语言中(例如 Google Go,以及某种程度上的 Python),但 C++ 并不是其中之一。虽然编译器当然有可能检测到派生类没有对基类中声明为“虚拟”的内容重用关键字“virtual”(或者更重要的是,派生类声明了一个与基类并且它尚未在基类中声明为虚拟),事实上,许多编译器都有设置在发生这种情况时发出警告(甚至错误消息)。但在现阶段,在语言中提出这样的要求是不切实际的,因为存在太多不那么严格的代码。此外,开发人员始终可以选择比语言更严格的规则,并且可以调高编译器警告级别。

That is a good question, and I certainly agree that it is good style to redeclare a method virtual in the derived class if it has been declared virtual in the base class. While there are some languages that build style into the language (e.g. Google Go and, to some extent, Python), C++ is not one of those languages. While it certainly is possible for a compiler to detect that a derived class does not reuse the keyword "virtual" for something declared "virtual" in a base class (or, more importantly, that the derived class declares a function of the same name as the base class and it has not been declared virtual in the base class), there are, in fact, settings on many compilers to issue warnings (and even error messages) in the event that this happens. At this stage, though, it would not be practical to institute such a requirement in the language as there exists too much code that is not that strict. Moreover, developers can always choose to be more stringent than the language and can turn up compiler warning levels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文