模板化虚拟函数的C++设计帮助
C++ design help for templated virtual function
我正在尝试基于一个通用类实现许多类,该类使用boost.threadpool抽象线程池。我有一些可以工作的东西(在osx 10.7.2上的Xcode中),但我真的不确定它的设计是否好,甚至是否安全(主要是因为我在网上读到了关于使用模板的虚拟成员函数的内容)。我正在寻找一些关于实现这样的东西的最佳方式的风格建议。我在这里边学习边学习,所以我知道很多这都是"糟糕的状态"。。。
我有一个名为"工作队列"的基类,如下所示:
template <typename T>
class Workqueue{
private:
pool *pThreadPool;
public:
Workqueue (int);
void Start (T);
void Schedule (T);
virtual bool Process(T) {return true;}
};
template <typename T> Workqueue<T>::Workqueue(int thread_count){
pThreadPool = new pool(thread_count);
}
template <typename T> void Workqueue<T>::Start(T data){
pThreadPool->schedule(boost::bind(&Workqueue::Process,this, data));
pThreadPool->wait();
}
template <typename T> void Workqueue<T>::Schedule(T data){
pThreadPool->schedule(boost::bind(&Workqueue::Process,this, data));
}
然后,我基于这个类定义了一个新的服务,如下所示:
struct Service1Data{
string item_data;
};
class MyService : public Workqueue<Service1Data> {
public:
MyService (int);
bool Process (Service1Data);
};
MyService::MyService(int workers) : Workqueue<Service1Data>(workers) {}
bool MyService::Process(Service1Data service_data){
cout << "in process (" << service_data.item_data << ")" << endl;
return true;
}
(为了保持简单,我删除了尽可能多的代码,以便在它不断提交新作品时永远运行)。我使用的服务是这样的:
MyService *service1 = new MyService(5);
Service1Data x;
x.item_data = "testing";
service1->Start(x);
// will wait until no more work.
delete service1;
所以我的具体问题是:
首先(请温柔一点…)这种形式不好吗?有更好的方法吗?(为什么?)
其次,考虑到虚拟/模板问题,这是否安全?我在某个地方读到,如果类本身是模板化的,应该是安全的,我想我理解vtable的基本问题,但真的不确定具体情况。
第三,基本工作队列类需要在'h'文件中具有成员定义和要链接的类定义。不知道为什么会这样——我想这是一个与虚拟/模板问题有关的链接器问题,所以让我很紧张。
所有的帮助都得到了感激。。
Chris
我认为,您不应该将数据处理与队列处理 我的意思是,你的 然后你就可以用虚拟函数解决所有的问题了。则CCD_ 4类应当同意CCD_ 5并且可以提供处理功能。 另外,我怀疑你是否真的需要 如果您需要一个用于服务的通用接口,则应该明确指定它&分别地你的继承链看起来不清楚。继承意味着是。为什么 编辑:代码如下: 编辑:我最初认为用法为:Workqueue
中不应该有Process
方法。Data
可以自己处理,或者您的队列可以获得作为(模板?)参数的处理函数。Workqueue
。您可以在YourService
中使用pThreadPool
。YourService
是Workqueue
我不相信我认为YourService
可以使用任何类型的队列。但是用法是聚合。template<typename Processor>
class WorkQueue
{
public:
WorkQueue(int count, Processor& processor):_processor(processor),_pool(count) {}
template <typename Data>
void schedule(const Data& data)
{
_pool->schedule(std::bind(&Processor::process,_processor, data));
}
template <typename Data>
void run(const Data& data)
{
schedule(data);
_pool->wait();
}
private:
Processor& _processor;
pool _pool;
};
class Service
{
public:
virtual void run() = 0;
virtual ~Service() {}
};
struct ServiceParams
{
int param;
};
class MyService: public Service
{
friend class WorkQueue<MyService>;
public:
MyService(const ServiceParams& params): _params(params), _queue(1, *this) {}
void run() { return _queue.run(_params); }
private:
ServiceParams _params;
WorkQueue<MyService> _queue;
void process(const ServiceParams& params) {std::cout <<"hello, worldn";}
};
ServiceData data;
Service* service = new MyService(data);
service->run();
delete service;
我可以明显指出的一些小事情:
- 当您可以创建自动对象时,过度使用new和delete
例如,如果您的工作队列和池具有相同的生存期,则:
template <typename T> class Workqueue
{
private:
pool threadPool;
// // etc
};
template< typename T >
Workqueue::Workqueue( int numThreads ) : threadPool( numThreads )
{
}
基类需要一个虚拟析构函数,目前Start可以调用Schedule,而不是两次实现同一行代码(使用boost::bind)。理想情况下,只接受int成员的构造函数将被声明为显式的。
您可能需要逻辑来等待线程完成。
我认为一个好的设计应该将排队和工作/任务分开。在您的设计中,两者紧密耦合。如果你想为每种类型的工作/任务创建单独的池,这种设计是很好的。
另一种方法是创建一个单独的包含process
函数的Work
类。然后您的MyService
将扩展Work
。CCD_ 16类将接受CCD_ 17,也就是说任何派生类也将接受。这种方法本质上更为通用。所以同一个工作队列可以接受不同类型的工作/任务。下面的代码说明将更清楚。
如果您想为不同类型的数据提供不同的池,也可以使用添加此方法。它在本质上更灵活。
template <typename T>
class Work{
T data; // contains the actual data to work on
public:
Work(T data) : data(data) {} // constructor to init data
virtual bool Process(T) {return false;} // returns false to tell process failed
T getData() { return data; } // get the data
};
class MyWork : public Work<Service1Data> {
public:
MyService (Service1Data data) :
Work(data) {}
bool Process (Service1Data); // Implement your work specific process func
};
bool MyWork::Process(Service1Data service_data){
cout << "in process (" << service_data.item_data << ")" << endl;
return true;
}
class Workqueue{
private:
pool *pThreadPool;
public:
Workqueue (int);
void Start (Work);
void Schedule (Work);
};
Workqueue::Workqueue(int thread_count){
pThreadPool = new pool(thread_count);
}
void Workqueue::Start(Work workToDo){
pThreadPool->schedule(boost::bind(&Work::Process,this, workToDo.getData()));
pThreadPool->wait();
}
void Workqueue::Schedule(Work data){
pThreadPool->schedule(boost::bind(&Work::Process,this, workToDo.getData()));
}
用法
Service1Data x;
x.item_data = "testing";
MyWork myWork(x);
Workqueue wq = new Workqueue(5);
wq->Start(myWork);
// will wait until no more work.
delete service1;
现在,要为不同类型的工作/任务实现不同的池,请创建两个具有不同池大小的Workqueue
,然后只给其中一个工作类型,另一个工作类别。
注意:上面的代码可能包含语法错误,它只是用来传达设计的。将其视为伪代码。
- 需要帮助设置在C++中使用的Potrace
- 在指针的帮助下,文本文件中单词的频率
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 如何在Qbutton的帮助下更改Q对话框的宽度
- 需要帮助将结构数组传递给函数
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 需要帮助在 c++ 中将字符串转换为字符 ----错误 "const char *" 类型的值不能用于初始化 "char" 类型的实体
- 有人可以帮助我处理正则表达式吗?
- C++调用具有 *this 属性的单个帮助程序函数
- C++:需要帮助了解运算符重载错误
- 需要以下代码的帮助,下面的代码有什么问题
- CS1 项目帮助C++
- 用于检查值是否为其任何参数的帮助程序函数
- 需要有关此 if 语句的帮助
- 类型限定宏帮助程序
- CoreCLR 中的检测探查器 - 将帮助程序程序集加载到 dotnet 进程的方法
- NS3 插槽混淆(需要帮助理解)
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 需要帮助查找内存泄漏
- 有人可以帮助我理解这些参数/参数吗?