【问题标题】:Function overriding in C++ works without 'virtual'C++ 中的函数覆盖在没有“虚拟”的情况下工作
【发布时间】:2014-01-31 07:00:10
【问题描述】:

我有一个包含一些函数的类(没有一个是虚拟的),另外 2 个类公开继承了该类。在两个子类中,我都覆盖了基类的相同功能。

在 main(位于同一个文件)中创建所有三个类的对象后,我用基类对象调用原始函数,用派生类对象调用覆盖函数。

我希望所有 3 个函数调用都能从基类运行原始函数(因为我没有在代码中的任何地方使用“虚拟”),但实际上我使该函数的每个版本都根据类在它被定义(3 个不同的版本)。

我的类 Base & Derived 如下:

struct Base
{
   void foo();
};

struct Derived : Base
{
   void foo();
};

主要:

int main()
{
   Derived d;
   d.foo();
}

如果不使用“虚拟”,我认为 d.foo() 应该运行 Base::foo()。

【问题讨论】:

  • 请出示相关的C++代码。我们无法真正理解您的所有问题。
  • 为什么不向我们显示代码而不是描述它? SSCCE (sscce.org) 将是理想的选择。
  • 没有代码,不清楚你在问什么
  • 很抱歉没有提供代码,这是我在工作中遇到的事情,我只是想出了什么不工作的主要想法,没有代码可以提供,不过,有一条评论“delnan”在这里不知何故消失了,他实际上是对的。
  • @theexplorer:如果没有其他方法,通常可以帮助您中获取该想法并形成代码,然后将其绘制给自己。例如我的回答。

标签: c++ virtual overriding


【解决方案1】:

不是“压倒一切”...而且它不需要。

struct Base
{
   void foo();
};

struct Derived : Base
{
   void foo();
};

int main()
{
   Derived d;
   d.foo();
}

如果我对您的理解正确,那么您期望它执行 Base::foo(),因为这些函数不是虚拟的,因此一个不会覆盖另一个。

但是,在这里,您不需要虚拟调度:继承规则只是声明您将获得适合您运行它的对象类型的正确函数。

当您需要虚拟调度/覆盖时,情况略有不同:当您使用 indirection 时:

int main()
{
   Base* ptr = new Derived();
   ptr->foo();
   delete ptr;
}

在上面的 sn-p 中,结果将是 Base::foo() 被调用,因为表达式 ptr->foo() 不知道 *ptr 真的Derived。它只知道ptrBase*

这就是添加virtual(并且这样做,使一个函数覆盖另一个)使魔术发生的地方。

【讨论】:

  • 你的派生应该是从base派生的吗?
  • @Lightness Races in Orbit:我对此也有疑问 :) 我希望没问题:当创建这样的 Base 对象数组时:Base array[2]={derivedObj1, derivedObj2}; array[0]。 foo(); 运行 Base 的 foo() 而不是 Derived 的 foo(),即使它在 Base 类中是“虚拟的”。另一方面,当创建这样的 Base 对象数组时:Base *array[2]={new Derived(), new Derived()}; array[0].foo(); 运行 Derived 的 foo()... 我可以得到第一个选项像第二个一样工作多态?
  • @theexplorer:不,you're slicing your objects。它们实际上被复制到Base 对象中进行存储。
  • @Lightness Races in Orbit:好的,我明白了。谢谢。
【解决方案2】:

你不能覆盖不是虚拟的东西。非虚拟成员函数是根据实例对象的类型静态调度的。

【讨论】:

    【解决方案3】:

    你可以通过“覆盖”一个函数来作弊,方法是让它成为一个间接调用某些东西的内联函数。类似(C++03

     class Foo;
     typedef int foo_sig_t (Foo&, std::string&);
     class Foo {
        foo_sig_t *funptr;
     public:
        int do_fun(std::string&s) { return funptr(*this,s); }
        Foo (foo_sig_t* fun): funptr(fun) {};
        ~Foo () { funptr= NULL; };
        // etc
     };
    
     class Bar : public Foo {
        static int barfun(Bar&, std::string& s) { 
           std::cout << s << std::endl;
           return (int) s.size();
        };
      public: 
        Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
         // etc...
      };
    

    及以后:

      Bar b;
      int x=b.do_fun("hello");
    

    官方说这不是重载虚函数,但看起来很接近虚函数。但是,在我上面的Foo 示例中,每个Foo 实例都有自己的funptr,不一定由类共享。但是所有Bar 实例共享相同 funptr 指向相同的barfun

    顺便说一句,使用C++11 lambda anonymous functions(内部实现为closures)会更简单更短。

    当然,virtual functions 实际上通常是通过类似的机制实现的:对象(带有一些 virtual 的东西)隐含地以隐藏字段(可能是“命名”_vptr)开头,给出vtable(或虚拟方法表)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 2019-06-29
      • 1970-01-01
      • 2021-03-27
      • 2014-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多