[多态]用输入的名字来生成子类的对象
第一次写多态的程序,遇到一个问题,就是输入一个类名字,怎样方便地 new 出一个子类的对象。
假设基类是 base,子类有 A,B。
开始我是这样的:
if (name == base::class_name())
p = new base;
else if (name == A::class_name())
p = new A;
else if (name == B::class_name())
p = new B;
else
p = 0;
我觉得这样不好,不容易维护,想添加新的子类的话,要改的地方很多,而且容易漏掉。
于是我就想有一个“管理器”来给我管理就好了,我只要在最开始的时候向管理器注册一下,以后用名字就可以方便地从管理器里分配一个新的对象了。
初步想的话,每个类应该有两个 static 成员函数,一个用来给出类的名字,另一个则用于分配一个对象。
可以写出基类如下:
class base
{
public:
~base ();
static const char* class_name ()
{
static const char _name[]="base";
return _name;
}
static base* alloc () { return new base; }
};
这样,每个类都有一对 class_name 和 alloc,查到 class_name 后就可以通过 alloc 分配一个对象。
下面是管理器的代码:
template <class base_t>
class poly_alloc
{
typedef base_t* value_type;
typedef value_type (*alloc_type)();
vector<pair<const char*, alloc_type> > alloces;
public:
void
reg (const char* name, alloc_type a)
{
alloces.push_back (make_pair (name, a));
}
value_type
alloc (const string& name)
{
value_type _new = 0;
for (int i = 0; i < alloces.size(); i++)
if (name == alloces[i].first)
{
_new = (*alloces[i].second)();
break;
}
return _new;
}
};
用 reg 去注册一个子类(当然也可以是基类),以后用 alloc 就可以分配了。如:
poly_alloc<mybase> pa;
pa.reg (mybase::class_name(), mybase::alloc);
pa.reg (A::class_name(), A::alloc);
pa.reg (B::class_name(), B::alloc);
mybase* p;
p = pa.alloc ("A");
delete p;
整个代码如下:
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <utility>
using namespace std;
class mybase
{
public:
virtual ~mybase ()
{}
static mybase*
alloc ()
{
mybase* _new = new mybase;
return _new;
}
virtual const char*
name ()
{
return class_name();
}
static const char*
class_name ()
{
static const char _name[]="base";
return _name;
}
virtual void
foo ()
{
cout << name() << " done" << endl;
}
};
class A: public mybase
{
public:
static mybase*
alloc ()
{
A* _new = new A;
return _new;
}
const char*
name ()
{
return class_name();
}
static const char*
class_name ()
{
static const char _name[]="A";
return _name;
}
void
foo ()
{
cout << name() << " done" << endl;
}
};
class B: public mybase
{
public:
static mybase*
alloc ()
{
B* _new = new B;
return _new;
}
const char*
name ()
{
return class_name();
}
static const char*
class_name ()
{
static const char _name[]="B";
return _name;
}
void
foo ()
{
cout << name() << " done" << endl;
}
};
template <class base_t>
class poly_alloc
{
typedef base_t* value_type;
typedef value_type (*alloc_type)();
vector<pair<const char*, alloc_type> > alloces;
public:
void
reg (const char* name, alloc_type a)
{
alloces.push_back (make_pair (name, a));
}
value_type
alloc (const string& name)
{
value_type _new = 0;
for (int i = 0; i < alloces.size(); i++)
if (name == alloces[i].first)
{
_new = (*alloces[i].second)();
break;
}
return _new;
}
};
int
main ()
{
poly_alloc<mybase> pa;
pa.reg (mybase::class_name(), mybase::alloc);
pa.reg (A::class_name(), A::alloc);
pa.reg (B::class_name(), B::alloc);
mybase* p;
cout << "There are class (base, A, B)" << endl;
string str;
do
{
cout << "Please input a class name:";
cin >> str;
p = pa.alloc (str);
if (p == 0)
break;
p->foo ();
delete p;
}
while (true);
system ("Pause");
return 0;
}