Important: This question is getting quite long,if this is the first time you’re reading this I suggest you start near the bottom as the solution is there in a round about way,but the code is a bit smelly.
阅读tutorial on templates之后,我能够更改现有类以支持泛型类型.但是,许多对象已经依赖于此,所以我正在寻找一种使方法通用而不是整个类的方法.
// foobar1.h // Don't want the entire class to be generic. //template<class T> class FooBar1 { public: template<class T> T Foo(); } // foobar2.h class FooBar2 : public FooBar1 { } // foobar1.cpp template<class T> T FooBar1::Foo() { return something; } // test.cpp FooBar1 fb1; FooBar2 fb2 = fb1.Foo<FooBar2>();
这应该不起作用,还是我在其他地方遇到的一个错误?
undefined reference to
FooBar2 Foo<FooBar2>()
为了实现我想要实现的目标,我在C#中如何做到这一点……
public class FooBar1 { public T Foo<T>() where T : FooBar1 { return something; } } public class FooBar2 : FooBar1 { } FooBar1 fb1 = new FooBar1(); FooBar2 fb2 = fb1.Foo<FooBar2>();
有什么方法可以做类似于C的事情吗?
更新1:
刚刚纠正了一些小的语法细节(我的意思是让Foo公开,然后返回T,而不是FooBar2).仍然得到编译器错误…当我删除模板行为时,错误消失了,到目前为止答案说我正在做的是有效的…但如果是,那么为什么我仍然得到错误?谢谢你的回答!
更新2:
Josh,这是实际的源代码(嗯,我认为是相关的,anwyay – 如果你认为我已经跳过了重要的一点,请告诉我).
// ImageMatrix.h class ImageMatrix : public VImage { public: // ... varIoUs functions ... template<class T> T GetRotatedCopy(VDouble angle); } // ImageFilter.h class ImageFilter : public ImageMatrix { // ... varIoUs functions ... } // ImageMatrix.cpp template<class T> T ImageMatrix::GetRotatedCopy(VDouble angle) { // ... create a new instance of ImageMatrix and return it. } // ImageProcessor.cpp ImageFilter filter2 = filterPrototype.GetRotatedCopy<ImageFilter>(90);
这是实际的编译器错误:
/home/nick/Projects/ViMRID/vimrid/Debug/libvimrid.so: undefined reference to `vimrid::imaging::processing::ImageFilter vimrid::imaging::ImageMatrix::GetRotatedCopy(double)’
更新3:
顺便说一下,除了实现线之外的所有东西都位于一个库中;所以它是从一个单独的二进制文件调用的……这有关系吗?更正;它都在同一个图书馆里.但是所有块都是不同的文件.
更新4:
当我注释掉实现行(ImageFilter filter2 = filterPrototype …)时,它构建得很好,所以看起来就是这一行导致它……
更新5(已解决?):
还有问题……这可能是命名空间的问题吗?抓紧,好吧,我现在已经掌握了模板的概念! :)模板定义必须与声明一起在标题中(对吗?) – 所以现在我已将声明移到ImageMatrix.h中,所有内容都会编译.但是,我必须使用dynamic_cast来使其正常工作;这是正确的吗?如果我要离开,请纠正我!
// This is in the header file! // Help!!! This looks really really smelly... template<class T> T ImageMatrix::GetRotatedCopy(VDouble angle) { ImageMatrix image = _getRotatedCopy(angle); ImageMatrix *imagePtr = ℑ return *dynamic_cast<T*>(imagePtr); }
更新6:
参考更新5,当我不使用dynamic_cast时……
template<class T> T ImageMatrix::GetRotatedCopy(VDouble angle) { ImageMatrix image = _getRotatedCopy(angle); ImageMatrix *imagePtr = ℑ //return *dynamic_cast<T*>(imagePtr); return *imagePtr; }
……我收到这个错误……
../src/imaging/processing/../ImageMatrix.h: In member function ‘T vimrid::imaging::ImageMatrix::GetRotatedCopy(vimrid::VDouble) [with T = vimrid::imaging::processing::ImageFilter]’: ../src/imaging/processing/ImageProcessor.cpp:32: instantiated from here ../src/imaging/processing/../ImageMatrix.h:45: error: conversion from ‘vimrid::imaging::ImageMatrix’ to non-scalar type ‘vimrid::imaging::processing::ImageFilter’ requested make: *** [src/imaging/processing/ImageProcessor.o] Error 1
更新7:
另外,如果我在更新6中没有使用所有那些臭臭的代码……
class ImageMatrix : public VImage { public: template<class T> T GetRotatedCopy(VDouble angle); private: ImageMatrix _getRotatedCopy(VDouble angle); }; template<class T> T ImageMatrix::GetRotatedCopy(VDouble angle) { return _getRotatedCopy(angle); }
…我得到了与更新6中相同的错误.
解决方法
class FooBar1 { public: template<class T> T Foo(); }; class FooBar2 : public FooBar1 { }; template<class T> T FooBar1::Foo() { return T(); } int main() { FooBar1 fb1; FooBar2 fb2 = fb1.Foo<FooBar2>(); }
您遇到的问题是您将FooBar1 :: Foo()的返回类型指定为FooBar2,您应该只将其作为FooBar2.
如果你想为FooBar2做特定的事情,你可以专门研究FooBar2:
template<> FooBar2 FooBar1::Foo<FooBar2>() { return FooBar2(); }
编辑:
听起来你在编译器没有找到模板化GetRotatedCopy的定义时遇到问题. C中的模板相当挑剔,通常的做法是将整个模板实现放在头文件中.你可以试试这个:
class ImageMatrix : public VImage { public: // ... varIoUs functions ... template<class T> T GetRotatedCopy(VDouble angle) { // ... create a new instance of ImageMatrix and return it. } };
编辑:
我找不到gcc文档,但这里有关于显式模板实例化和库的microsoft’s documentation,它给出了一些关于发生了什么的想法.您可能希望按照我之前的建议在头中包含实现,或者在库中调用GetRotatedCopy,或者在库中显式实例化它.有关语法,请参见下面的veefu’s answer.
与C#不同的原因是C语言中的模板实际上为每个不同的模板参数组合创建了一个全新的类/函数.例如矢量<诠释>是一个完全不同的类(使用不同的编译方法集)而不是vector< string>.有关更好的解释,请参阅Kevin’s answer.
至于当你不使用模板时错误消失,这实际上并没有告诉你多少,因为直到你实际实例化一个模板,它不会
RE更新5,6,7
您的dynamic_cast不起作用,只有当指针实际指向您要转换的类的实例时,才能使用它. (它的工作方式类似于C#中的as运算符).
我现在怀疑,你想要的是CRTP.你开始使用ImageFilter的一个实例,并希望在其上使用基类方法,并获得ImageFilter的新副本.尝试这些方面:
template <class T> class ImageMatrix { public: T GetRotatedMatrix() { return T(); } }; class ImageFilter : public ImageMatrix<ImageFilter> { }; int main() { ImageFilter filterPrototype; ImageFilter otherFilter = filterPrototype.GetRotatedMatrix(); }
否则,如果您真的想从ImageMatrix开始并将其转换为ImageFilter,则必须在ImageFilter上添加一个构造函数,该构造函数采用ImageMatrix.