关于OOP:替代C++中的虚静态函数?

Alternative to virtual static functions in c++?

在头文件.hpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  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中:

1
2
3
4
5
  /*Some Return Type*/ Derived1::func(/*Some Datatype*/){
  }

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

这显然失败了,因为无法重写子类中的静态方法。但如何获得上述功能呢?

我必须这样称呼:

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

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

在头文件.hpp中:

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

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

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


调用一个没有对象的虚拟函数是一种相反的感觉,因为分辨率取决于对象的类型。在这种情况下,您可能需要调用相同的函数取决于对象的类型或指定类显式地,没有对象。这很容易用两个功能,一个静态,一个虚拟。(通常,虚拟一号将直接转到静态。)

编辑:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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);
    //  ...
};

等等,在所有的派生类中。这个习惯了获取用于序列化的类型名,例如:

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

同时作为原始的RTTI(大约20年前):

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

(我们已经确立了一条规则,那就是你能获得的唯一途径类的名称是通过使用这些函数中的一个来实现的。那有效地将类的名称内部化,并允许简单的指针比较。在我们之前的系统中在那时,这很重要。)


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  struct  Base
  {
      // nothing
  };

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

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

这允许您拨打:

1
2
Derived1::foo();
Derived2::foo();

为基类型调用它,并期望编译器找出您所指的子类型无法工作:

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

你可能想看看crtp或者类型特征来寻找替代方法。


你可以做得有点下流=)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//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:很奇怪,您不想在派生类中声明这个函数,因为当您使用虚拟函数时,应该在派生类中声明它们。