[多态]用输入的名字来生成子类的对象

cxjddd 2003-12-21 02:22:44
第一次写多态的程序,遇到一个问题,就是输入一个类名字,怎样方便地 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;
}
...全文
91 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
superS 2003-12-23
  • 打赏
  • 举报
回复
根据我的理解,动态创建应该是在RTTI的基础上或者说是同时拥有的能力。他每个类的那个静态struct里面有很多成员,分别负责RTTI,动态创建,序列化。
cxjddd 2003-12-23
  • 打赏
  • 举报
回复
还是要看 MFC 啊。

MFC 里不是可以给每个对象都分配一个 ID 吗?然后用这个 ID 就可以找到对象了。

也有人说看看 RTTI 的实现:)
superS 2003-12-21
  • 打赏
  • 举报
回复
MFC就是这么做的,动态创建。

他每一个类有一个静态的成员变量,一个struct,记录类名和创建实例的静态成员函数地址,由于它是单根的,于是他可以把所有类的这个struct联接成一个链表,每当要创建一个类,就遍历一遍。

《深入浅出MFC》讲的很详细哦。
cxjddd 2003-12-21
  • 打赏
  • 举报
回复
对 MFC 不太熟悉,现在还没有在 MFC 里这样生成过对象。

请问在 MFC 里叫什么啊?
codingcoding 2003-12-21
  • 打赏
  • 举报
回复
看看mfc的源代码就知道具体怎么实现了.
cxjddd 2003-12-21
  • 打赏
  • 举报
回复
楼上这样用宏很不错,呵呵

不过,觉得不够直观,如果比较大一点的子类就不行了。

嗯,宏还是比较危险的,少用就少用:)
daizh 2003-12-21
  • 打赏
  • 举报
回复
楼主的想法不错。
对于你这个问题,其实有个很实用的方法,就是使用宏定义,我建议你用这个方法。
class base;
#define DERIVED_CLASS(name,type)\
class name##base : public base{\
.....\
你需要的实现功能\
.....\
}

使用是只需DERIVED_CLASS(name,type);
cxjddd 2003-12-21
  • 打赏
  • 举报
回复
发现一个东东,指向 static 成员函数的指针,如要指向上面的 A::alloc,这样就可以了:
mybase* (*an_alloc)();
an_alloc = A::alloc;

唉,C++ 的 OO 一直没学好:(

64,643

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧