Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数模板:访问子类';基类中的重载函数_C++_Templates - Fatal编程技术网

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。我必须管理我无法将您的答案应用到我的代码中现在可以了。非常感谢您(和其他人)的时间和解释,非常感谢!