C++ 为什么我要在C++;?是否有一种权衡?

C++ 为什么我要在C++;?是否有一种权衡?,c++,virtual-functions,C++,Virtual Functions,我知道虚拟方法为什么以及如何工作,大多数时候人们都告诉我应该始终将一个方法标记为虚拟方法,但是,如果我不打算覆盖它,我不明白为什么。我也知道有一个小小的内存问题 请解释我为什么要将所有方法标记为虚拟方法,以及如何权衡 代码示例: class Point { int x, y; public: virtual void setX(int i); virtual void setY(int i); }; (这个问题不等于,因为我想知道权衡,因为在本例中的编程语言

我知道虚拟方法为什么以及如何工作,大多数时候人们都告诉我应该始终将一个方法标记为虚拟方法,但是,如果我不打算覆盖它,我不明白为什么。我也知道有一个小小的内存问题

请解释我为什么要将所有方法标记为虚拟方法,以及如何权衡

代码示例:

class Point
{
   int x, y;
   public:
      virtual void setX(int i);
      virtual void setY(int i);
};

(这个问题不等于,因为我想知道权衡,因为在本例中的编程语言是C++,而不是C语言)

OBS:如果有语法错误,我很抱歉,英语不是我的母语。

不,您不应该“将所有方法标记为虚拟”

如果希望该方法是虚拟的,则将其标记为虚拟。如果没有,请删除关键字


与常规方法相比,虚拟方法的开销较大。如果你想了解更多这方面的信息,请查看Wikipedia关于的内容。

事实并非如此,也就是说,如果你不需要虚拟函数,就不要使用它。同样根据比亚恩·斯特劳斯特鲁普

在C++中:--

  • 虚拟函数有轻微的性能损失。通常情况下,它太小,不会产生任何影响,但在一个紧密的循环中,它可能是 意义重大

  • 虚函数将每个对象的大小增加一个指针。同样,这通常是无关紧要的,但是如果您创建 数以百万计的小物体,这可能是一个因素

  • 具有虚拟函数的类通常意味着要从中继承。派生类可以替换部分、全部或全部 虚拟功能。这会造成额外的复杂性和复杂性 复杂性是程序员的死敌。例如,派生的 类可能无法很好地实现虚拟函数。这可能会损坏零件 依赖于虚函数的基类的


  • 使方法虚拟化的成本很小(代码更多、更复杂、二进制文件更大、方法调用更慢),如果类不是从中继承的,则不会带来任何好处。类需要为继承而设计,否则从类继承就是自讨苦吃。因此,不应该总是使每个方法都是虚拟的。告诉你这件事的人可能太高兴了。

    C++的基本原则之一是,你不需要为你不需要的东西付费<代码>虚拟函数在时间和空间上的成本都高于普通成员函数。因此,你不应该总是使用它们,不管你是否真的需要它们

    使成员函数非虚的真正原因是强制类不变量

    使所有成员功能虚拟化的建议通常意味着:

  • 给出建议的人不理解课堂,或者
  • 给出建议的人不理解OO设计
  • 是的,在一些情况下(例如,一些抽象基类,其中唯一的类不变量是特定函数的存在),所有函数都应该是虚拟的。但这些都是例外。在大多数类中,虚拟函数应该限制在那些您真正希望允许派生类提供新的/不同的行为的类中


    至于vtables和虚拟函数调用的开销等问题的讨论,我认为它们是正确的,但它们忽略了真正重要的一点。一个特定的函数是否应该是虚拟的主要是类设计的问题,其次是函数调用开销的问题。两者的作用不同,因此尝试比较开销几乎没有意义。

    并非所有函数都应标记为虚拟函数

    事实上,有一种强制执行前置/后置条件的模式明确要求公共成员不是虚拟的。其工作原理如下:

    class Whatever
    {
    public:
      int frobnicate(int);
    protected:
      virtual int do_frobnicate(int);
    };
    
    int Whatever::frobnicate(int x)
    {
      check_preconditions(x);
      int result = do_frobnicate(x);
      check_postconditions(x, result);
      return result;
    }
    
    由于派生类不能重写公共函数,因此它们不能删除前置/后置条件检查。但是,它们可以覆盖执行实际工作的受保护的副本。

    (编辑-我通过重复的C问题来回答这个问题,但我认为答案仍然有用!编辑以反映这一点:)

    事实上,C#有一个很好的“官方”理由:

    第一句话是:

    C#语言的设计是为了使不同库中的基类和派生类之间的版本控制能够不断发展并保持向后兼容性

    因此,如果您正在编写一个类,最终用户可能会生成派生类,并且不同版本可能会失去同步……突然之间,它开始变得重要起来。如果您仔细保护了代码的核心部分,那么如果您更新了一些东西,人们仍然可以使用旧的派生类(希望如此)

    另一方面,如果您认为在派生类的作者更新到您的最新版本之前没有人能够使用派生类,那么一切都可以是虚拟的。我在几个允许修改的“早期访问”游戏中看到过这种情况——当游戏版本增加时,突然有很多修改都被破坏了,因为它们依赖于单向工作的东西……并且它们发生了变化。(好的,并非所有更改都与此相关,但有些更改与此相关。)

    这实际上取决于您的使用场景。如果人们可以继续使用你的旧版本,也许他们不在乎你是否已经更新了它,并且很乐意继续将它与他们的派生类一起使用。在一个大的商业场景中,当有人更新某个东西时,将所有东西虚拟化可能是一个很好的解决办法


    这也适用于C++吗?我不明白为什么不——C++也用于大规模的项目,也会面临多个并发版本的危险。< / P>怎么告诉你的?code>virtual函数调用通常涉及vtable查找,不能内联。如果你不需要它们,不要使用它们。检查Wrox Professional