从静态类继承

Inheriting from a static class

本文关键字:继承 静态类      更新时间:2023-10-16

我有一系列静态类,用于填充和访问std::map中的数据。

由于它们是静态的,所以很容易设置它,以便只有在需要的时候才会填充地图,并且只需要填充一次。

大致如下:

class MyClass
{
public:
  string at(int key)
  {
    PopulateEmptyMap();
    return myMap.at(key);
  }
private:
  void PopulateEmptyMap()
  {
    if(!myMap.empty())
      return;
    PopulateMap();
  }
  void PopulateMap()
  {
    myMap[1] = "str1";
    myMap[2] = "str2";
  }
  static map<int, string> myMap;
};

实际的类更复杂,有多个映射,但你已经明白了。

我有一系列像这样的类,除了映射的类型和值之外,它们几乎完全相同。

与其让多个类都复制相同的代码,我希望代码存在于一个地方,但我不知道如何做到这一点

我的第一个想法是从一个拥有所有共享代码的模板类中继承。函数PopulateMap将变成纯虚拟的,然后由每个继承类实现。当然,这是行不通的,因为函数不可能同时是静态的和虚拟的。

我有什么选择来做我正在尝试的事情?

没有静态类这回事。您所描述的类只有静态数据,这些数据被填充一次,然后再使用。您可以拥有任意数量的非静态函数,包括虚拟函数和常规函数,只要它们只处理静态成员数据即可。

这是你想要的东西。

#include <iostream>
#include <string>
#include <map>
// A base class template that has a virtual function
// to allow derived classes to fill up the map.
template <typename Key, typename Value>
class MyTemplateClass
{
   public:
      Value at(Key const& key)
      {
         PopulateEmptyMap();
         return myMap.at(key);
      }
      void PopulateEmptyMap()
      {
         if(!myMap.empty())
            return;
         PopulateMap();
      }
   protected:
      virtual void PopulateMap() = 0;
      static std::map<Key, Value> myMap;
};
// Define the static member data of the class template.
template <typename Key, typename Value>
std::map<Key, Value> MyTemplateClass<Key, Value>::myMap;
// Define a sub-calss of MyTemplateClass that works
// int as key and string as value.
class MyClass1 : public MyTemplateClass<int, std::string>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = "str1";
         myMap[2] = "str2";
      }
};
// Define a sub-calss of MyTemplateClass that works
// int as key and int as value.
class MyClass2 : public MyTemplateClass<int, int>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = 10;
         myMap[2] = 20;
      }
};
int main()
{
   MyClass1 c1;
   std::cout << c1.at(1) << std::endl;
   std::cout << c1.at(2) << std::endl;
   MyClass2 c2;
   std::cout << c2.at(1) << std::endl;
   std::cout << c2.at(2) << std::endl;
}

注意:

如果使用int作为键,使用int作为值来定义从MyTemplateClass继承的另一个派生类,您将看到意外的行为。MyTemplateClass<int, int>只能有一个实例化。

// This will lead to unexpected behavior. You will get either 10 and 20 in
// the map or 30 and 40. You will not get all four in the map.
// If the behavior of MyClass2 seems sane, the behavior of MyClass3 will seem
// the opposite, or vice versa.
class MyClass3 : public MyTemplateClass<int, int>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = 30;
         myMap[2] = 40;
      }
};

但是,您可以使用MyTemplateClass的第三个参数来解决这个问题。

#include <iostream>
#include <string>
#include <map>
template <typename Key, typename Value, typename Derived>
class MyTemplateClass
{
   public:
      Value at(Key const& key)
      {
         PopulateEmptyMap();
         return myMap.at(key);
      }
      void PopulateEmptyMap()
      {
         if(!myMap.empty())
            return;
         PopulateMap();
      }
   protected:
      virtual void PopulateMap() = 0;
      static std::map<Key, Value> myMap;
};

template <typename Key, typename Value, typename Derived>
std::map<Key, Value> MyTemplateClass<Key, Value, Derived>::myMap;
class MyClass1 : public MyTemplateClass<int, std::string, MyClass1>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = "str1";
         myMap[2] = "str2";
      }
};
class MyClass2 : public MyTemplateClass<int, int, MyClass2>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = 10;
         myMap[2] = 20;
      }
};
class MyClass3 : public MyTemplateClass<int, int, MyClass3>
{
   protected:
      virtual void PopulateMap()
      {
         myMap[1] = 30;
         myMap[2] = 40;
      }
};
int main()
{
   MyClass1 c1;
   std::cout << c1.at(1) << std::endl;
   std::cout << c1.at(2) << std::endl;
   MyClass2 c2;
   std::cout << c2.at(1) << std::endl;
   std::cout << c2.at(2) << std::endl;
   MyClass3 c3;
   std::cout << c3.at(1) << std::endl;
   std::cout << c3.at(2) << std::endl;
}

这对我有用。希望对你有用。

更新

有几个选项可以选择,它们不需要在堆栈上创建对象。

所有static成员

您可以设计类,使所有内容都可以通过static成员函数访问。

#include <iostream>
#include <string>
#include <map>
template <typename Key, typename Value, typename Derived>
class MyTemplateClass
{
   public:
      static Value at(Key const& key)
      {
         PopulateEmptyMap();
         return myMap.at(key);
      }
      static void PopulateEmptyMap()
      {
         if(!myMap.empty())
            return;
         Derived::PopulateMap();
      }
   protected:
      static std::map<Key, Value> myMap;
};

template <typename Key, typename Value, typename Derived>
std::map<Key, Value> MyTemplateClass<Key, Value, Derived>::myMap;
class MyClass1 : public MyTemplateClass<int, std::string, MyClass1>
{
   public:
      static void PopulateMap()
      {
         myMap[1] = "str1";
         myMap[2] = "str2";
      }
};
int main()
{
   // Access the data without needing to create an object.
   std::cout << MyClass1::at(1) << std::endl;
   std::cout << MyClass1::at(2) << std::endl;
   // They are also accessible using an object.
   MyClass1 c1;
   std::cout << c1.at(1) << std::endl;
   std::cout << c1.at(2) << std::endl;
}

Singleton模式

另一种可能适用于您的方法是使用singleton模式。

#include <iostream>
#include <string>
#include <map>
template <typename Key, typename Value, typename Derived>
class MyTemplateClass
{
   public:
      Value at(Key const& key)
      {
         PopulateEmptyMap();
         return myMap.at(key);
      }
      void PopulateEmptyMap()
      {
         if(!myMap.empty())
            return;
         PopulateMap();
      }
   protected:
      virtual void PopulateMap() = 0;
      static std::map<Key, Value> myMap;
};

template <typename Key, typename Value, typename Derived>
std::map<Key, Value> MyTemplateClass<Key, Value, Derived>::myMap;
class MyClass1 : public MyTemplateClass<int, std::string, MyClass1>
{
   public:
      static MyClass1* instance()
      {
         static MyClass1 theInstance;
         return &theInstance;
      }
      void PopulateMap()
      {
         myMap[1] = "str1";
         myMap[2] = "str2";
      }
   private:
      // Disallow creation of objects by clients
      MyClass1() {}
      ~MyClass1() {}
};
int main()
{
   // Access the data using the instance() interface.
   std::cout << MyClass1::instance()->at(1) << std::endl;
   std::cout << MyClass1::instance()->at(2) << std::endl;
}