我有很多抽象类字母的子类,如A、B、C、D等。字母有一个整数id变量,每个字母子类都分配一个唯一的ID。
然后我又上了一堂课,叫它字母。字母表
list<shared_ptr<Letter>> 成员。问题是..。我想优雅地添加字母的B和C或其他子类到特定的字母实例中。我认为最方便的方法是以某种方式使用子类的整数id。换句话说,我希望能够有类似于Alphabet.addLetter(int )的东西,所以如果我做了字母表1.add(14),它将以某种方式将H类的shared_ptr添加到列表中。
是否有一种优雅的方法来做到这一点,避免在每次添加或删除B、C、D、E等类时需要不断更新的大型if语句?我希望有某种模板解决方案,但我不太熟悉诸如工厂和模板这样的高级c++概念。我想要的是某种向量/地图,将我的I转换成类名,这样我就可以做一些类似的事情。
list.push_back(shared_ptr<classVector(i)>(new classVector(i))或者诸如此类的东西,尽管我不知道这是否可能。
谢谢!
附注:我选择了Alphabet的例子,因为我不想给出不必要的细节。显然,我不是在用这样愚蠢的方式设计字母,lol。
编辑:我正在努力使这件事有意义。我的目标是能够非常迅速地创建新的信函子类,只需付出最少的努力。我想避免输入看起来像.
list.push_back(shared_ptr<X>(...));每次我写一封新的信。这有意义吗?
发布于 2014-05-15 21:14:00
如果我正确地理解了您,使用所谓的工厂模式,这是相对容易的。
如果可以列出所有派生类型:
信件标题:
struct Letter {
enum LetterEnum {LetterA, LetterB, LetterC, LetterCount};
virtual ~Letter() {} //base types should always have virtual destructor
virtual void foo() = 0;
static std::unique_ptr<Letter> construct(LetterEnum c);
};实现头:
struct A : Letter {
void foo() override;
};
struct B : Letter {
void foo() override;
};
struct C : Letter {
void foo() override;
};信件正文:
std::unique_ptr<Letter> Letter::construct(Letter::LetterEnum c)
{
switch(c) {
case Letter::LetterA : return make_unique<A>();
case Letter::LetterB : return make_unique<B>();
case Letter::LetterC : return make_unique<C>();
default: throw ...;
}
}用法:
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}如果不能列出所有派生类型:
允许派生类型向Letter类注册,然后Letter可以使用它来创建每个派生类型。这样,添加和删除派生类型不涉及对任何其他文件的更改。简单!
struct Letter {
virtual ~Letter() {} //destructor is always virtual when inheretence is involved
....
//this is a "shared" function in the Letter class itself
//it takes a letter, and returns a dynamically allocated instance
//of the derived type corresponding with that letter
static std::unique_ptr<Letter> construct(char c);
//this typedef represents the actual function that returns
//each dynamically allocated derived type
typedef std::function<std::unique_ptr<Letter>()> letter_ctor;
//this is a "shared" function in the Letter class itself
//it takes a letter, and a function that creates derived types,
//and saves them inside the container ctors
static bool register(char c, letter_ctor func);
private:
//this is a "shared" member in the Letter class.
//There is only one shared by all of the Letters. Like a global.
//When you give it a letter, it gives you a function.
//and is VERY fast for large numbers of entries
static std::unordered_set<char,letter_ctor> ctors;
};在您的实现文件中:
//here's the function that derived types register themselves with
//pretty straightforward, just inserts the pair into the unordered_map
bool Letter::register(char c, Letter::letter_ctor func)
{return Letter::ctors.insert(std::make_pair(c,std::move(func))).second;}
//and here's the function that creates the derived types
//it checks if the letter is in the unordered_map
//if the letter isn't there, it throws an exception
//otherwise, it calls the function associated with that letter
//which creates the derived type on the heap, and returns a pointer to it
std::unique_ptr<Letter> Letter::construct(char c)
{
auto it = Letter::ctors.find(c);
if (it == Letter::ctors.end())
throw ...;
return it->second(); //construct that letter
}然后派生类型执行以下操作:
//you know this part
struct LetterA : public Letter
{
....
};
//derived types have to register themselves:
//this is a global, so when the program loads, it automatically calls this
//even before main runs*
//it registers the letter 'A' and a function that creates a LetterA class on the heap
static bool registerA = Letter::register('A', [](){return make_unique<LetterA>();});然后,您可以很容易地创建树派生类型!
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}*它并不总是在main之前被调用。如果有问题,将bool init_A();放在A头中,bool init_A(){return true;}放在A实现文件中,在主文件中放置static bool AInit=init_A();,这将强制执行它。然而,在实践中,这几乎是从来不需要的。
顺便提一句,这取决于有一个make_unique,它应该在C++11中,但是由于疏忽而被忽略了。它将在C++14中。同时,请使用以下命令:
template<class T, class...Us>
std::unique_ptr<T> make_unique(Us&&...us)
{return std::unique_ptr<T>(new T(std::forward<Us>(us)...));}发布于 2014-05-15 21:05:40
这一点很难理解,但我认为您想要的是以下内容:
// where make_unique<> is from C++14 in std:: or like:
template <typename T, typename ... TArgs>
std::unique_ptr<T> make_unique(TArgs &&... args) {
return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}
struct Letter {
virtual ~Letter() { }
virtual void foo() = 0;
};
template <unsigned int N> struct LetterCode; // Note: no default implementation!
struct Alphabet {
// Indexed access, if you'll have 1 of each type max:
std::vector<std::unique_ptr<Letter>> v;
// If you don't need parameters, as mentioned in comments below ...
template <unsigned int N>
void addLetterN() {
if (N > v.size() + 1) { v.resize(N + 1); }
v[N] = make_unique<LetterCode<N>::type>(); // see below ...
}
// If your coding is complete from 0...N, this does the whole shebang.
template <unsigned int N>
void addLettersN() {
addLetters<N - 1>();
addLetterN<N>();
}
template <>
addLettersN<0>() {
addLetterN<0>();
}
};如果您需要反序列化之类的数字代码,并且永远不需要构造函数参数,您可以使用一个类型特征模板,如下面所示,静态地“注册”这些类型:
struct B : Letter {
B(int n, bool b, char const *name);
void foo() override;
};
template <> struct LetterCode<2> { using type = B; };
struct C : Letter {
C(double d);
void foo() override;
};
template <> struct LetterCode<3> { using type = C; };
void bar() {
Alphabet a;
a.addLetterN<2>();
a.addLetterN<3>();
// --OR--
a.addLettersN<3>(); // will do 0...3 in one fell swoop.
for (auto &i : a.v) {
if (!i) { continue; } // v is sparse, unlike l
i->foo();
}如果需要传递广义构造函数参数,则可以使用完美转发,这是为类似这种情况而设计的,并消除了旧类型工厂对枚举ID等的需求:
struct Alphabet {
std::list<std::unique_ptr<Letter>> l;
// variadic factory that chucks new (shared_ptr) objects in the list.
template <typename T, typename ... TArgs>
void addLetter(TArgs && ... args) {
l.push_back(make_unique<T>(std::forward<TArgs>(args)...));
}
};
void baz() {
Alphabet a;
a.addLetter<B>(1, false, "pony");
a.addLetter<C>(2.718281828);
for (auto &i : a.l) {
i->foo(); // can call virtual funcs here all you want ...
}
}发布于 2014-05-15 21:00:20
我的理解是,您希望创建其中一个类的实例,依赖于与创建实例的类相关的id。
如果是的话,请看一看工厂的图案。有很多工厂实现,也是基于模板递归扩展的打字员。
伪码:
Factory<A,B,C,D> fac; // the list must be changed, if some more classes comes and goes
id_type id;
list<base> l;
l.push_back=fac.Create(id);自己实现这样一个类也很简单。
https://stackoverflow.com/questions/23688289
复制相似问题