【发布时间】:2009-07-25 03:39:21
【问题描述】:
我正在尝试编写工厂设计模式的 C++ 实现。我也想使用共享对象和动态加载来做到这一点。我正在实现一个名为 new
_animal() 的函数,它传递了一个字符串。如果字符串为“dog”,则需要查看是否有一个class dog注册到共享对象中,并创建一个dog对象。如果字符串是“cat”,它需要找到注册的 class cat 并返回它的一个对象。函数 new_animal() 事先并不知道将传递给它的字符串。因此,如果传递了具有相应未注册类的字符串,则会出错。这是代码 -
creator.hpp -
#ifndef CREATOR_HPP
#define CREATOR_HPP
#include <string>
class Animal {
public :
virtual string operator() (const string &animal_name) const = 0;
virtual void eat() const = 0;
virtual ~Animal() { }
};
class AnimalCreator {
public :
// virtual Animal *create() const = 0;
virtual ~AnimalCreator() { }
};
typedef Animal* create_animal_t();
typedef void destroy_animal_t(Animal *);
#endif
cat.hpp -
#ifndef CAT_HPP
#define CAT_HPP
#include "creator.hpp"
#include <iostream>
#include <string>
class cat : public Animal {
public :
string operator() (const string &animal_name) const { return "In cat () operator"; }
void eat() const { cout << "cat is eating" << endl; }
};
class catCreator : public AnimalCreator {
public :
}theCatCreator;
#endif
cat.cpp -
#include "cat.hpp"
#include <iostream>
using namespace std;
extern "C" Animal *create() {
cout << "Creating cat ..." << endl;
return new cat;
}
extern "C" void destroy(Animal* a) {
delete a;
}
dog.hpp -
#ifndef DOG_HPP
#define DOG_HPP
#include <string>
#include "creator.hpp"
class dog : public Animal {
public:
string operator() (const string &animal_name) const { return "In dog"; }
void eat() const { cout << "Dog is eating" << endl; }
};
class dogCreator : public AnimalCreator {
public:
}theDogCreator;
#endif
dog.cpp -
#include "dog.hpp"
#include <iostream>
using namespace std;
extern "C" Animal *create() {
cout << "Creating dog" << endl;
return new dog;
}
extern "C" void destroy(Animal *aa) {
delete aa;
}
main.cpp -
#include "creator.hpp"
#include "cat.hpp"
#include "dog.hpp"
#include <iostream>
#include <string>
#include <map>
#include <dlfcn.h>
map<string, AnimalCreator *> AnimalMap;
void initialize() {
AnimalMap["dog"] = &theDogCreator;
AnimalMap["cat"] = &theCatCreator;
}
Animal * new_animal(const string &animal) {
static bool isInitialised (false);
if (!isInitialised) {
initialize();
isInitialised = true;
}
AnimalCreator *theAnimalCreator = AnimalMap[animal];
if (!theAnimalCreator) {
cout << "error: " << animal << " not registerd" << endl;
exit(1);
}
Animal *theAnimal = theAnimalCreator->create();
return theAnimal;
}
int main() {
void *animal = dlopen("animal", RTLD_LAZY);
if (!animal) {
cout << "error is dlopen" << endl;
exit(1);
}
create_animal_t* new_animal = (create_animal_t*) dlsym(animal, "create");
if (!new_animal) {
cout << "error is dlsym create" << endl;
exit(1);
}
destroy_animal_t* destroy_animal = (destroy_animal_t*) dlsym(animal, "destroy");
if (!destroy_animal) {
cout << "error is dlsym destroy" << endl;
exit(1);
}
Animal *a = new_animal("dog");
Animal *b = new_animal("cat");
a->eat();
b->eat();
destroy_animal(a);
destroy_animal(b);
dlclose(animal);
return 0;
}
生成文件 -
# macros
CC = g++
CFLAGS = -g -Wall
MODFLAGS = -fpic -shared
LDFLAGS = -ldl
OBJECTS = main.o animal
# targets
all: foo
foo: $(OBJECTS)
$(CC) -o foo $(OBJECTS) $(LDFLAGS)
animal: dog.cpp cat.cpp
$(CC) $(CFLAGS) $(MODFLAGS) dog.cpp cat.cpp -o animal
clean:
rm -f foo $(OBJECTS)
当我使用 make animal 创建共享对象时,这就是我得到的 -
bash-2.05$ make animal
g++ -g -Wall -fpic -shared dog.cpp cat.cpp -o animal
ld: fatal: symbol `create' is multiply-defined:
(file /var/tmp/ccgDUpwo.o type=FUNC; file /var/tmp/ccv0VjHp.o type=FUNC);
ld: fatal: symbol `destroy' is multiply-defined:
(file /var/tmp/ccgDUpwo.o type=FUNC; file /var/tmp/ccv0VjHp.o type=FUNC);
ld: fatal: File processing errors. No output written to animal
collect2: ld returned 1 exit status
make: *** [animal] Error 1
我知道方法 create() 和 destroy() 有多个定义,因此会出现错误。但同时,我不能在 main.cpp 中使用任何特定于类的 create() 方法,因为这样做不会使其通用。我将 create() 和 destroy() 函数保留在类定义之外。我还使用 extern "C" 来确保编译器不会添加名称修饰,并保持共享库中的符号名称与函数名称相同。
有人可以给我一些关于如何解决这个问题的提示吗?可以在类设计中进行任何更改吗?
感谢您耐心阅读上面的代码。
-Onkar Deshpande
【问题讨论】:
标签: c++ design-patterns oop shared-libraries