我有一系列静态类,用于填充和访问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函数将变为纯虚拟,然后由每个继承类实现。当然,这不起作用,因为该功能不可能是静态的和虚拟的。
我可以选择做什么?
答案 0 :(得分:2)
没有静态类这样的东西。您正在描述一个只有一次填充并在此后使用的静态数据的类。您可以拥有任意数量的非静态函数 - 虚拟和常规 - 只要它们只使用静态成员数据。
这似乎是你正在寻找的东西。
#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;
}
<强>注意:强>
如果您使用MyTemplateClass
作为键并且int
作为值来定义继承自int
的另一个派生类,您将看到意外行为。只能有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 pattern。
#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;
}