【问题标题】:Determining if a derived class overrides a method from a base class确定派生类是否覆盖基类中的方法
【发布时间】:2011-06-01 03:58:52
【问题描述】:
class B {
virtual int foo();
};

class D : public B {
virtual int foo() { cout<<"D\n"; }
};

int B::foo()
{
   /* how do i tell if this->foo() is overridden by a subclass, or if it will */
   /* simply recurse into B::foo()? */
   this->foo();
}

main()
{
D d;
d.B::foo();
}

【问题讨论】:

  • 可能没有可靠的方法。为什么要这样做?
  • 我同意 Oli - 像普通人一样调用 d.foo()。
  • 我想用一些额外的个人观点来补充我的回答。我尽我最大的努力从不质疑为什么有人想做某事。我不可能知道他们为什么要做某事,我只知道他们问了一个问题。我认为尝试解决他们的问题并提供他们可能没有想到的替代方案是可以的,但是像“像正常人一样做”这样的陈述既没有建设性也没有帮助。
  • @Andrew:我的评论会写得更爽快,但是,好吧,你得写这么多角色。另外,作为一个一直在这种cmet的另一端,绝对不是正常人的人,我很有信心知道这种cmet什么时候幽默,什么时候不幽默。
  • 质疑我为什么要这样做是毫无意义的。说“只需调用 d.foo()”是一个迟钝的答案。我可以花一个小时来解释为什么这样做会对我的情况有所帮助,这将使您能够引用以其他方式实现我想要的方法。但我已经知道如何通过围绕 C++ 的这个限制进行工程来完成我想要的。所以没有必要把大家的时间浪费在一堆废话上。

标签: c++ virtual rtti


【解决方案1】:

回答:你不能。

如果有什么可以扩展的,我会扩展。

【讨论】:

    【解决方案2】:

    最安全的方法是根本不覆盖 foo(),但如果您不信任您的程序员,则允许覆盖从基类调用的 OnFoo() 函数。 MFC 做了很多这样的工作来确保一些默认行为(而不是防止递归)。

    然后,同样在静态级别,任何实现 OnFoo() 的东西都可以通过“在文件中查找”轻松发现。

    例如(未针对语法/编译进行测试,也不是线程安全的)

    class B
    {
    public:
        B()
        {
            m_bInFoo=false;
        } 
    
        int foo()
        {
            if( !m_bInFoo )
            {
                m_bInFoo=true;
    
                int nRet = OnFoo();
    
                m_bInFoo=false;
    
                return nRet;
            }
    
            return 0;// probably throw exception
        }
    
    protected:
        // inherited classes override OnFoo(), and never call OnFoo();
        virtual int OnFoo(){ return 0 };
    
    private:
        bool m_bInFoo;
    }
    

    【讨论】:

      【解决方案3】:

      我什至讨厌提供这个..但是在这里

      int B::foo()
      {
      std::cout << "B" << std::endl;  
      if (typeid (*this) != typeid(B))
          this->foo();
      return 0;
      }
      

      编辑

      我想证明它在 MSVC++ 2010 中有效。

      #include "stdafx.h"
      #include <iostream>
      
      class B {
      public:
      virtual int foo();
      };
      
      class D : public B {
      public:
      virtual int foo() {
          std::cout<<"D\n"; return 0; 
      }
      };
      
      int B::foo()
      {
      std::cout << "B" << std::endl;  
      
      /* how do i tell if this->foo() is overridden by a subclass, or if it will */
      /* simply recurse into B::foo()? */
      if (typeid (*this) != typeid(B))
          this->foo();
      
      return 0;
      }
      
      
      int main(int argc, _TCHAR* argv[])
      {
      D d;
      d.B::foo();
      
      B b;
      b.foo();
      return 0;
      }
      

      输出

      B
      D
      B
      

      证明它并不总是有效

      把D改成这个就不行了

      class D : public B { };
      

      【讨论】:

      • 那行不通。它不知道 foo() 是否被覆盖,事实上,如果不是,您的代码将在 D 对象上对 foo() 的任何调用中无限递归;正是OP想要避免的。除了调用 foo() 的 B 实际上是否是更指定的版本之外,它实际上并不能帮助您找出任何东西......就是这样。如果人们在检查答案的有效性之前不直接分发分数,那么分数会更有意义。
      • @ Noah Roberts 你是对的,如果 D 不覆盖 B::foo 它将递归。这也可以通过使用堆栈展开来解决。在堆栈上创建一个变量,一旦进入 B::foo(),在线程本地存储中设置一个标志,如果 B:foo() 通过同一个堆栈再次进入,并尝试创建另一个变量,它可以检查是否标志已设置然后退出。一旦堆栈展开,变量的销毁就可以取消设置标志。我的解决方案解决了他给出的确切问题,这是我的错,因为我没有阅读其他可能发生的情况。
      【解决方案4】:

      一种方法是使foo()纯虚函数B中,并且也定义它。这样您就可以确保B 的派生类必须 定义foo()。这里是B,

      class B
      {
      public:
              virtual int foo() = 0; //pure virtual function
      };
      
      //pure virtual function also has a default implementation!
      int B::foo()
      {
              std::cout << "B" << std::endl;  
              this->foo(); //this will call the overridden foo() in the derived class!
              return 0;
      }
      

      如果 B 的派生类没有实现 foo(),那么你甚至不能创建这样的派生类的实例!

      在 ideone 上查看完整的工作代码:http://www.ideone.com/m8O2s

      顺便说一句,我个人的看法是,这样的类设计一开始就不好。如果你从派生类 foo() 中调用 B::foo() 会怎样?递归?

      【讨论】:

      • 这使得他无法实例化 B 的实例。我们不知道他是否还想创建 B 类型的对象。
      • 是的,我当然意识到有很多方法可以围绕它进行工程设计,但我的问题是 C++ rtti 中是否有内置方法来做我想做的事情。
      【解决方案5】:

      正如其他人指出的那样,没有可靠的方法来做到这一点。我敦促您重新考虑您的设计...

      【讨论】:

      • 嗯,是的,如果我可以重新设计以前开发人员的笨拙代码,那就太好了,但可惜现在还没有。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-31
      • 2011-09-11
      • 2017-06-22
      • 2018-12-17
      • 2021-06-17
      相关资源
      最近更新 更多