C++ 函数模板:访问子类';基类中的重载函数
我有一个基类C++ 函数模板:访问子类';基类中的重载函数,c++,templates,C++,Templates,我有一个基类First和一个派生类Second。在基类中有一个成员函数create和一个虚拟函数run。在Second的构造函数中,我想调用函数First::create,该函数需要访问其子类“run()函数的实现。一位同事建议使用函数模板,因为首先无法明确知道它的子类。听起来怪怪的?下面是一些代码: First.h #pragma once #include <boost/thread/thread.hpp> #include <boost/chrono/chrono.hpp
First
和一个派生类Second
。在基类中有一个成员函数create
和一个虚拟函数run
。在Second
的构造函数中,我想调用函数First::create
,该函数需要访问其子类“run()
函数的实现。一位同事建议使用函数模板,因为首先
无法明确知道它的子类。听起来怪怪的?下面是一些代码:
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 ) );
}
};
#pragma once
#include "first.h"
class Second : public First
{
public:
Second();
~Second();
void run();
};
Second.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 ) );
}
};
#pragma once
#include "first.h"
class Second : public First
{
public:
Second();
~Second();
void run();
};
Second.cpp
#include "First.h"
First::First() {}
First::~First() {}
#include "Second.h"
Second::Second()
{
First::create<Second>();
}
void Second::run()
{
doSomething();
}
#包括“Second.h”
第二个::第二个()
{
第一个::create();
}
void Second::run()
{
doSomething();
}
我在First::create()处遇到错误代码>显示错误:不允许使用类型名称。那么这个错误的原因是什么呢?我想我还没有完全了解模板的全部机制,但是-我对这个主题非常陌生。首先你必须在标题中添加模板定义,否则链接器将很难找到实例化的模板。
第二:现在双关语结束了,我假设你从第一个衍生出了第二个。这被称为“奇怪的重复模板模式”(CRTP)
由于基类已被专门化,并且派生类的类型已被刻入其类型中,因此无需将其任何函数作为模板(您没有这样做),并且只需调用基类的函数,而无需指定模板参数:
template <class SubClass>
struct First {
void create() {
SubClass& sub = static_cast<SubClass&>(*this);
mThread = make_unique<std::thread>( [&](){sub.run();} );
}
};
struct Second : First<Second> {
Second() { create(); }
void run();
};
模板
结构优先{
void create(){
子类和子类=静态类型(*本);
mThread=make_unique([&](){sub.run();});
}
};
结构二:第一{
第二个(){create();}
无效运行();
};
一些注释:
- 您不需要首先限定
内部的访问
- 您只需调用
create
,这是一个继承的方法,而且由于Second
不是模板,因此不需要添加限定条件或帮助编译器进行查找
- 与标准相比,更喜欢
std::thread
,它已经在标准中使用了一段时间
- 与拥有所有权的原始指针相比,更喜欢
std::unique_ptr
- 我更喜欢lambdas而不是
bind
——读起来更清晰
- 我创建了两个类
struct
,以便在默认情况下公开成员函数,并在示例代码中保存一行。除此之外,类
没有区别
尽管您可以按照Kerrek SB和Arne Mertz的“建议”使用CRTP,但这里有一个使用成员函数模板的解决方案:
class First
{
public:
First();
~First();
virtual void run() = 0;
boost::thread* m_Thread;
// vvvvvvvvvvv this declares a non-template member function `create`
void create(); // (better remove it)
// vvvvvvvvvv this declares a member function template `create`
template< class ChildClass >
void create();
};
代码中的其他一些(可能)问题:
- 您没有虚拟DTOR,因此删除指向基类子对象的指针将调用UB
- 因为
&ChildClass::run
的类型是void(Second::*)()
,所以需要进行向下转换
create
在Second
的构造函数内调用,该构造函数将调用Second::run
(或您提供的任何模板参数),该函数在类Second
中的最终重写。如果在从Second
派生的类中重写该函数,则在Second
的构造函数中不会调用该重写
- 第一个
的dtor应该分离
或加入
boost线程,否则调用dtor时如果线程仍在运行,将调用std::terminate
run
不必是虚拟的。在本例中,完全相同的代码在run
是虚拟的,甚至在First
中声明将函数模板的定义放在标题中。请参见,例如,简单地将
模板
放入First.h?不幸的是,对错误没有任何影响。不,整个函数体。它需要在头文件中,因为函数模板实例化的定义需要在使用它们的每个TU中可用。好的,我将整个模板…create function body放入First.h中,但它仍然在First::create()中显示该错误代码>在Second.cpp中,请同时向我们显示标题。非常感谢您的回答。遗憾的是,我不得不使用boost::thread。我必须管理我无法将您的答案应用到我的代码中现在可以了。非常感谢您(和其他人)的时间和解释,非常感谢!