我有一个基类 First
和一个派生类 Second
. 在基类中有一个成员函数 create
和一个虚函数 run
. 在 Second
的构造函数中,我想调用函数 First::create
,它需要访问其子类' run()
函数的实现 . 一位同事建议使用函数模板,因为 First
可以't know it'明确地显示子类 . 听起来怪怪的?这是一些代码:
First.h
#pragma once
#include <boost/thread/thread.hpp>
#include <boost/chrono/chrono.hpp>
class First
{
public:
First();
~First();
virtual void run() = 0;
boost::thread* m_Thread;
void create();
template< class ChildClass >
void create()
{
First::m_Thread = new boost::thread(
boost::bind( &ChildClass::run , this ) );
}
};
First.cpp
#include "First.h"
First::First() {}
First::~First() {}
Second.h
#pragma once
#include "first.h"
class Second : public First
{
public:
Second();
~Second();
void run();
};
Second.cpp
#include "Second.h"
Second::Second()
{
First::create<Second>();
}
void Second::run()
{
doSomething();
}
我在 First::create<Second>();
收到错误,说错误:不允许输入类型名称 . 那么什么's the reason for this error? I assume I didn' t得到模板的整体机制,但是 - 我对这个话题很新 .
2 回答
虽然您可以使用CRre作为Kerrek SB和Arne Mertz的“建议”,但这是使用成员函数模板的解决方案:
对于模板,您应该在头文件中提供定义,因为定义必须在每个需要它的TU中可用(而不仅仅在一个TU中) .
最简单的方法是在类本身内提供成员函数模板或类模板成员的定义:
现在,如果要在
Second
类中调用此成员函数模板,则必须显式提供模板参数:您的代码的一些其他(可能)问题:
您没有虚拟dtors,因此删除指向基类子对象的指针将调用UB .
需要进行向下转换,因为
&ChildClass::run
的类型为void (Second::*)()
.在
Second
的ctor中调用create
,它将调用Second::run
(或您提供的任何模板参数),该类函数在Second
中的最终覆盖 . 如果在从Second
派生的类中覆盖该函数,则不会在Second
的ctor中调用该覆盖 .First
的dtor应该是detach
或join
提升线程,否则如果在调用dtor时线程仍在运行,则会调用std::terminate
.run
在此示例中不必为虚拟,完全相同的代码可以在First
中虚拟或甚至声明为run
.首先,您必须在标头中放置模板定义,否则链接器将无法找到实例化的模板 . 第二:现在双关语已经完成了,我假设你从
First<Second>
派生了Second
. 这称为"Curiously Recurring Template Pattern"(CRTP) .由于基类已经是专用的并且具有类型的派生类的类型,因此不需要将它的任何函数作为模板(你没有),并且可以只调用基类的函数,没有指定模板参数:
一些注释:
您无需限定
First
内的访问权限你可以只调用
create
,它是一个继承的方法,由于Second
不是模板,因此无需添加限定条件或帮助编译器进行查找 .更喜欢
std::thread
而不是boost::thread
,它现在已经有一段时间了 .更喜欢拥有所有权的原始指针
std::unique_ptr
我更喜欢lambdas而不是
bind
- 对我来说更清楚 .我创建了两个类
struct
,以便默认情况下将成员函数设置为public,并在示例代码中保存一行 . 除了之外,class
没有区别 .