【问题标题】:Alternative to virtual static functions in c++?c++ 中虚拟静态函数的替代方案?
【发布时间】:2013-03-26 18:15:14
【问题描述】:

在头文件.hpp中:

  class Base{
        public:
              static /*Some Return Type*/ func(/*Some Datatype*/);
  }    
  class Derived1 public Base{
        public: 
               Derived1();
               ~Derived1();
  }
  class Derived1 public Base{
        public: 
               Derived2();
               ~Derived2();
  }

在cpp文件.cpp中:

  /*Some Return Type*/ Derived1::func(/*Some Datatype*/){
  }

  /*Some Return Type*/ Derived2::func(/*Some Datatype*/){
  }

这显然失败了,因为没有办法覆盖子类中的静态方法。但是如何获得上述功能呢?

我必须这样称呼:

  /*Some Return Type*/ result = Derived1::func(/*Some Datatype*/)
  /*Some Return Type*/ result = Derived2::func(/*Some Datatype*/)

我知道,抽象方法可以像下面这样在基类中定义,然后在派生类中定义:

在头文件.hpp中:

  class Base{
        public:
              virtual /*Some Return Type*/ func(/*Some Datatype*/) const = 0;
  }  

但问题是虚方法需要对象实例化,这不是我想要的。我想在不创建对象的情况下调用该方法。如果允许使用虚拟静态方法,它们就可以达到目的。

我能想到的唯一选择是在头文件的所有派生类中声明函数func(),并将其从基类中删除。有没有其他方法可以做到这一点?这样声明在 Base 类中只有一次,所有 Derived 类只需要定义它们,而不需要重新声明?

【问题讨论】:

  • 如果您有两个类BC,每个类都派生A 并覆盖A 上相同的理论“静态虚拟”方法,当您调用该方法时会发生什么A?应该使用BC 的实现吗?
  • 请说明你想如何调用这个函数,并说明应该选择哪个版本。
  • 是的,我看不出原因。您自己说过:“虚拟方法需要对象实例化”。当你调用一个静态成员函数时,你总是给它所属的类。
  • 其实A是我的抽象类。而且我永远不会在A 上调用该方法。没想到这个案子。现在我明白为什么不允许使用静态虚拟了,但是我该如何实现我的功能呢?除了在每个派生类中声明相同的函数之外,没有别的办法吗?
  • @NehalJ.Wani 如果你永远不会在A 上调用该函数,那么在A 上声明它是没有意义的。

标签: c++ oop inheritance static-methods virtual-functions


【解决方案1】:

一种可能性是只在派生类中定义它们:

  struct  Base
  {
      // nothing
  };

  struct Derived1 : public Base
  {
      static void func() { /*...*/ }
  };

  struct Derived2 : public Base
  {
      static void func() { /*...*/ }
  };

这允许你调用:

Derived1::foo();
Derived2::foo();

为基类型调用它并期望编译器找出你的意思是哪个子类型不能工作:

// How will the compiler know to choose 
// between Derived1:: func or Derived2:: func ?
Base::func(); 

您可能希望查看 CRTP 或类型特征以寻找替代方法。

【讨论】:

    【解决方案2】:

    在没有对象的情况下调用虚函数是一种反义词, 因为分辨率取决于对象的类型。 是您可能需要调用相同函数的情况 取决于对象的类型,或指定类 明确地,没有对象。这很容易通过使用来处理 两种功能,一种是静态的,一种是虚拟的。 (通常情况下, 虚拟的只会转发到静态的。)

    编辑:

    一个简单的例子(来自实际代码):

    #define DECLARE_CLASS_NAME(className)                               \
        static char className() { return STRINGIZE(className); }        \
        virtual char* getClassName() { return className(); }
    
    class Base
    {
    public:
        DECLARE_CLASS_NAME(Base);
        //  ...
    };
    
    class Derived : public Base
    {
    public:
        DECLARE_CLASS_NAME(Derived);
        //  ...
    };
    

    等等,在所有派生类中。这是用来 获取序列化的类型名称,例如:

    std::string typeName = pObj->getClassName();
    

    也作为原始 RTTI(大约 20 年前):

    if ( pObj->getClassName() == Derived::className() ) ...
    

    (我们已经制定了这样的规则,即您可以获得的唯一方法是 一个类的名称是通过使用这些函数之一。那 有效地内化了类的名称,并允许 简单的指针比较工作。在我们的系统上 继续努力,这很重要。)

    【讨论】:

    • 您能举个例子吗?
    【解决方案3】:

    你可以这样做有点 hacky =)

    //header file
    template<class T>
    struct base_t
    {
       static void do_smth();
    };
    
    struct derived1_t : base_t<derived1_t>
    {
    
    };
    
    struct derived2_t : base_t<derived2_t>
    {
    
    };
    
    //cpp file
    void base_t<derived1_t>::do_smth() // `note base_t<derived1_t>::` instead of `derived1_t::`
    {
       std::cout << "aaa" << std::endl;
    }
    

    PS:很奇怪,你不想在派生类中声明这个函数,因为当你使用虚函数时,你应该在派生类中声明它们

    【讨论】:

      猜你喜欢
      • 2011-02-12
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      相关资源
      最近更新 更多