简体   繁体   English

非模板化类的接口c ++

[英]non templated interfaces to templated classes c++

I have a hierarchy of templated classes that are constructed in one place and are passed around to other places to do some operations on them. 我有一个模板化类的层次结构,这些模板化类在一个地方构造并传递到其他地方以对它们进行一些操作。

For example, a class could be templated to some complex object which knows how to convert itself to a double, and the templated class has an operation to output this object as a double. 例如,可以将一个类模板化为某个复杂的对象,该对象知道如何将其自身转换为double型,并且该模板化的类具有将该对象输出为double型的操作。 An example of a utility function would be a function that outputs collections of this class as a table. 实用程序函数的一个示例是将此类的集合作为表输出的函数。

However, I do not want to pass in this type as a templated class, because the utility function should work on any concrete class variant because they can all represent themselves as double. 但是,我不想将这种类型作为模板化类传递,因为实用程序功能应可在任何具体的类变体上工作,因为它们都可以将自己表示为double。 Therefore I want to have some non-templated interface that has the 'represent as double' function. 因此,我想使用一些非模板化的接口,该接口具有“以double表示”功能。 Why does the following not work? 为什么以下方法不起作用?

#include "stdafx.h"

class Interface1
{
public:
    virtual int ReturnSomeInt();
};

template<typename myType>
class TClass1 : public Interface1
{
public:
    int ReturnSomeInt() {return 5;}
    void CalculateSomething(myType myValue) {}

    TClass1() {}
};

//---------------------------------------------

class Interface2 : public Interface1
{
public:
    virtual double ReturnSomeDouble();
};

template<typename myType>
class TClass2 : public TClass1<myType>, public Interface2
{
public:
    double ReturnSomeDouble() {return 9.2;}
    void CalculateSomethingElse(myType myValue) {}

    TClass2() {}
};

//---------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    Interface2 myInterface = TClass2<float>();
    int myInt = myInterface.ReturnSomeInt();
    double myDouble = myInterface.ReturnSomeDouble();
    return 0;
}

I get a link error 2019 about the fact that it could not find the symbol Interface2::ReturnSomeDouble(void) . 我收到一个链接错误2019,因为它找不到符号Interface2::ReturnSomeDouble(void) What could be the problem? 可能是什么问题呢?

virtual function (here Interface2::ReturnSomeDouble() ) cannot remain unimplemented, if the object of that type or its child types are instantiated. 如果实例化了该类型的对象或其子类型,则virtual函数(此处为Interface2::ReturnSomeDouble() )不能保持未实现。
Because, when the object is instantiated, it needs to populate the hidden class member vptr with the address/definition of virtual function, which is not found, so that linker error. 因为,当实例化对象时,它需要使用未找到的virtual函数的地址/定义填充隐藏的类成员vptr ,从而导致链接器错误。

Either you have to define their body or make it a pure virtual function (so that definition becomes optional). 您要么必须定义它们的主体,要么使其成为纯virtual函数(这样定义就成为可选的)。

What you have here is slicing . 您在这里正在切片 Your instance of TClass2 has been literally sliced when copied into variable 'myInterface' (the derived class part has been discarded). 当您将TClass2实例复制到变量“ myInterface”(派生的类部分已被丢弃)时,实际上已经对其进行了切片。 You need to instantiate TClass2 on the heap and then change 'myInterface' to be a pointer or reference for this to work. 您需要在堆上实例化TClass2,然后将“ myInterface”更改为指针或引用才能使其正常工作。

(And as a result of the slicing, your code is calling the unimplemented base class function. If you were to have made the base class function pure virtual, then you perhaps have gotten a more helpful error message). (作为切片的结果,您的代码正在调用未实现的基类函数。如果您要使基类函数成为纯虚拟的,则可能会得到一条更有用的错误消息)。

1 make the interface functions pure virtual by declaring them 1通过声明接口函数使其成为纯虚函数

virtual double ReturnSomeDouble() const = 0;

so that the linker doesn't look for the corresponding functions for the base class. 这样链接器就不会为基类寻找相应的函数。

2 declare interface1 to be a virtual base to avoid inheriting it twice in Tclass2 , though this is not critical for your code to compile 2将interface1声明为虚拟基础,以避免在Tclass2继承两次,尽管这对于您的代码进行编译并不重要

Since there were so many good answers to my question, I decided to re-post my code with all your helpful comments implemented. 由于我的问题有很多好的答案,因此我决定重新发布代码,并实施所有有用的注释。

#include "stdafx.h"

class Interface1
{
public:
    virtual int ReturnSomeInt()=0;
};

template<typename myType>
class TClass1 : public Interface1
{
public:
    int ReturnSomeInt() {return 5;}
    void CalculateSomething(myType myValue) {}

    TClass1() {}
};

//---------------------------------------------

class Interface2 : public Interface1
{
public:
    virtual double ReturnSomeDouble()=0;
};

template<typename myType>
class TClass2 : public TClass1<myType>, public Interface2
{
public:
    int ReturnSomeInt() { return TClass1<myType>::ReturnSomeInt(); }
    double ReturnSomeDouble() {return 9.2;}
    void CalculateSomethingElse(myType myValue) {}

    TClass2() {}
};

//---------------------------------------------

void WriteClassToConsole(Interface2& myInterface)
{
    std::cout << "My int:\t" << myInterface.ReturnSomeInt() << std::endl;
    std::cout << "My dbl:\t" << myInterface.ReturnSomeDouble() << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    TClass2<float> myClass;
    WriteClassToConsole(myClass);
    std::getchar();
    return 0;
}

Thanks to everyone who helped. 感谢所有提供帮助的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM