C++模板类中的非专用成员

C++ non-specialized member in template class

本文关键字:专用 成员 C++      更新时间:2023-10-16

我有一个关于模板类的问题。例如,参加这个类

template<class TBase> class CTemplateInherit : public TBase
{
public:
    virtual void DoNonSpecializedWork();
    virtual void DoTemplateWork();
    virtual ~CTemplateInherit();
};
// In header file
template<class TBase>
bool CTemplateInherit<TBase>::DoTemplateWork()
{
    std::wcout << L"CTemplateInherit::DoTemplateWork" << std::endl;
    TBase::DoWork();
    return true;
}
// In CPP file
bool CTemplateInherit::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

现在,我希望能够使用 dllexport 在 CPP 文件中定义非专用方法,并且只将专用化保留在标头中。通常,我想我可以将成员方法定义为模板化,但由于我从 TBase 继承,这是不可能的。

那么我怎么能把它分开呢?我只覆盖 TBase 中的 4 个方法,并希望能够将其他 40 个左右的方法保留为 DLL 中的 DLLEXPORT,而专用化在头文件中。

提前感谢您的建议!

我不太确定您要完成什么,但是在使用模板时,您需要确保根据需要实例化这些模板。将模板定义放在标头中时,可以从编译器获取隐式实例化:每当它看到使用了函数模板并且此模板的定义可见时,它就会实例化该模板。当您将模板放在其他位置时,编译器在需要时不会看到模板定义,因此不会隐式实例化它。但是,您可以自己实例化相应的函数模板,例如:

// In CPP file
template <class TBase>
bool CTemplateInherit<TBase>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}
template bool CTemplateInherit<SomeBase>::DoNotSpecializeWork();
template bool CTemplateInherit<SomeOtherBase>::DoNotSpecializeWork();

如果您不想更改hierarchy类。

1( specialize .cpp文件中所有需要的类型。

template<>
bool CTemplateInherit<First>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}
template<>
bool CTemplateInherit<Second>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}
template<>
bool CTemplateInherit<Nth>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

2( 使用

template<typename T>
bool CTemplateInherit<T>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

.cpp文件中,但在header中使用类似的东西

template class CTemplateInherit<First>;
template class CTemplateInherit<Second>;
template class CTemplateInherit<Nth>;

3(正如迪特马尔所建议的那样。

我认为缺少一条重要信息:非专用方法是否覆盖了TBase类的虚拟方法?这是这里的核心问题。

如果没有,那么您可以为非专用方法创建另一个类,并从CTemplateInherit类中的两个类继承(公开(。 问题解决了。

但是,如果非专用方法覆盖了 TBase 类的虚拟方法,则它只是稍微复杂一些:

解决方案 1(获取所有非专用函数并将它们重新分组到一个"详细信息"标头中。要么作为一组(非模板(自由函数(如果很容易将输入输出作为参数传递(,要么作为具有它所需的非专用数据成员的(非模板(类。然后,在相应的 cpp 文件(稍后将编译为 DLL(中定义所有这些函数(实现它们(。

然后,在CTemplateInherit类模板中,只需将非专用函数调用转发到"detail"函数集即可。由于模板默认为内联,因此开销将为零。如果您需要将"detail"函数重新分组到一个类(非模板(中,那么只需使用private继承,防止函数名称冲突。然后,您可以像任何其他继承的数据成员一样访问"detail"类的数据成员,并且可以将非专用函数调用转发到"detail"类实现,您可以将其编译为 DLL(如果您有合适的框架用于从 DLL 导出类(因为普通C++没有可靠的机制(, 但你的问题似乎暗示你这样做(。

此解决方案的唯一问题是烦人地创建了几个简单的转发功能。但恕我直言,这是将实现隐藏在 DLL 中的合理代价(几乎任何时候你想这样做,你最终都会编写一堆包装函数(。

解决方案 2(如果基类中有一组非专用的虚函数,那么该子集肯定不依赖于TBase的实际类型(我的意思是,这些函数的原型可以在没有它的情况下形成(。然后,这意味着您可以将该函数子集重新分组到另一个基类中,TBase应该从该基类继承。我们称之为TNonSpecialBase.此时,您可以设置以下层次结构:

class TNonSpecialBase {
  // set of pure-virtual functions that are not special.
};
// this is an example of a class that could act as a TBase:
class TExampleBase : public virtual TNonSpecialBase {
  // set of virtual functions that are special to TExampleBase.
};
class CNonSpecialDerived : public virtual TNonSpecialBase {
  // declaration of non-specialized functions that override the function in TNonSpecialBase.
};
template <typename TBase>
class CTemplateInherit : public TBase, public CNonSpecialDerived {
  // set of virtual functions that are specialized for the template argument TBase.
};

通过上述设置,专用函数必须最终位于 CTemplateInherit 的头文件中,但重新分组的非专用函数CNonSpecialDerived可以在单独的 cpp 文件中定义(并编译为 DLL(。这里的魔术技巧是使用虚拟继承来允许最终类具有基类TNonSpecialBase的单个虚拟表。换句话说,这允许类CNonSpecialDerived覆盖TBase中从TNonSpecialBase继承的虚函数,只要TBase不覆盖任何这些函数(在这种情况下,编译器会称其为歧义(。这样,用户可以处理指向TBase对象的指针,调用其任何虚拟函数,这将导致向CTemplateInherit实现(专用(或CNonSpecialDerived实现(大概在 DLL 中(调度。