关于C++:虚拟静态变量

Virtual static variable

我需要为类基的每个子代分配唯一的整数值,该子代应该可以通过使用指向这些类或其类型名的指针来访问。

我是这样实施的

1
2
3
4
5
class Base {
public:
  int idCompType = InvalidCompType;
  virtual int getCompType() = 0;
}

然后,在基的每个子代中,我应该声明idcomptype(用于模板)并重写getcomptype(用于指针):

1
2
3
4
5
class Real1: public Base {
public:
  int idCompType = 1;
  int getCompType() override { return idCompType; }
}

现在我可以找到从指针到基的comp类型

1
2
Base *comp = getComp(...);
std::cout << comp->getCompType();

或者在模板中使用类型名:

1
2
3
4
template <typename T>
int getType() {
  return T::idCompType;
}

在每个子类中,如果没有双重声明idcomptype和getcomptype(),是否有一种方法可以使其更简单?在对象Pascal中,我使用虚拟静态方法实现了这一点,但是它们在C++中是不允许的。

PS:问题不在于虚拟静态方法——虚拟静态方法只是可能的解决方案之一,我的问题是用其他语言解决的。


我的建议:

Base变更:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
   public:

      virtual int getCompType() = 0;

   protected:

      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

对派生类的更改:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Real1: public Base {
   public:
  static int getCompTypeImpl()
  {
     static int myType = Base::getNextCompType();
     return myType;
  }

  int getCompType() override
  {
     return getCompTypeImpl();
  }
};

下面是一个工作程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>

class Base {
   public:

      virtual int getCompType() = 0;

   protected:

      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

class Real1: public Base {
   public:

      static int getCompTypeImpl()
      {
         static int myType = Base::getNextCompType();
         return myType;
      }

      int getCompType() override
      {
         return getCompTypeImpl();
      }
};

class Real2: public Base {
   public:
      static int getCompTypeImpl()
      {
         static int myType = Base::getNextCompType();
         return myType;
      }

      int getCompType() override
      {
         return getCompTypeImpl();
      }
};

template <typename T> int getCompType()
{
   return T::getCompTypeImpl();
}

int main()
{
   Real1 v1;
   Real2 v2;

   std::cout << v1.getCompType() << std::endl;
   std::cout << v2.getCompType() << std::endl;

   std::cout << getCompType<Real1>() << std::endl;
   std::cout << getCompType<Real2>() << std::endl;
};

输出:

1
2
3
4
1
2
1
2


@r sahu答案的另一个变化是消除派生类中代码的重复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>

class Base {
   public:
      virtual int getCompType() const = 0;

      template <typename T>
      static int getCompTypeOf()
      {
         static int compType = getNextCompType();
         return compType;
      }

   private:
      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

template <typename Derived, typename DeriveFrom = Base>
class TypeAssigner : DeriveFrom {
   public:
      int getCompType() const override
      {
         return Base::getCompTypeOf<Derived>();
      }
};

class Real1: public TypeAssigner<Real1> {};

class Real2: public TypeAssigner<Real2> {};

class Real3 : public TypeAssigner<Real3, Real2> {};

int main()
{
   Real1 v1;
   Real2 v2;
   Real3 v3;

   std::cout << v1.getCompType() << '
'
;
   std::cout << v2.getCompType() << '
'
;
   std::cout << v3.getCompType() << '
'
;

   std::cout << Base::getCompTypeOf<Real1>() << '
'
;
   std::cout << Base::getCompTypeOf<Real2>() << '
'
;
   std::cout << Base::getCompTypeOf<Real3>() << '
'
;
};


这里是@sahu版本的一个微小变体。不要在每个派生类中实现相同的getCompTypeImpl(),而是将它放在Base类中。

1
2
3
4
5
template<typename T>
static int getCompTypeImpl()
{
    return getNextCompType<T>();
}

修改getNextCompType()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<typename T>
static int getNextCompType()
{
    auto iter = m_table.find(std::type_index(typeid(T)));
    if (iter != m_table.end())
    {
        return iter->second;
    }
    else
    {
        m_table.insert(std::make_pair(std::type_index(typeid(T)), ++nextType));
        return nextType;
    }
}

最后介绍了两个新的静态数据成员。

1
2
3
private:
    static std::map<std::type_index, int> m_table;
    static int nextType;

请在这里找到完整的代码。

诚然,这引入了两个新的静态成员,并做了更多的工作比原始版本的萨胡。但是,这消除了在所有派生类。