模板。没有类型在编译期间知道
可能noob问题。我希望使用CImg库来进行一些图像处理。他们中的一些可能是(8位)类型和其中一些(16位)。不幸的是,我不知道数据的类型,直到用户不选择文件来处理。当然,我可以这样做:模板。没有类型在编译期间知道
...
CImg <unsigned char> img_unisgned_char;
CImg <unsigned short> img_unisgned_short;
...
if (user_pick_8bit) img_unisgned_char.load_raw(fname,img_size_x,img_size_y);
if (user_pick_16bit) img_unisgned_short.load_raw(fname,img_size_x,img_size_y);
...
但CIMG方法99%,看起来完全为“无符号的字符”,“诠释”或“浮动”类型相同(如“load_raw”或“模糊”例如)。有什么办法可以做 - 我不知道 - 指针? - 因此,当用户选择文件我可以创造奇迹,如:
if (user_pick_8_bit) img = img_unisgned_char;
if (user_pick_16bit) img = img_unisgned_short;
...
//now no mother of what type is picked up by user I simply make:
img.load_raw(...);
你当然可以这样做,如果类模板CImg<T>
有一个父类。但是您会发现,您可以在不知道像素类型的情况下执行的一组操作仅限于加载和保存等操作。为了对图像内容进行操作,您需要保留具体的图像对象。
class CImgBase
{
// Functions that do not reference the pixel type can go here.
virtual void load_raw(...) = 0; // agnostic of pixel type
};
// CImg implements CImgBase interface
template<typename T>
class CImg : public CImgBase
{
void load_raw(...);
T get_pixel(int x, int y);
};
许多CImg
类模板的方法取决于T
参数,所以即使非相关的操作都抽象为一个超类,使用该库的代码中的许多部分将取决于类型反正也结束了。界面的一个重要部分似乎使用了数据类型,因此可能有一种方法可以使一个suoerclass只有非依赖方法,这在某种程度上可以使用。
或许下面可以工作:
class SuperCimg {
public:
// expose the non dependent methods as virtual pure
virtual Tfloat linear_atX(/* ... */) = 0;
// etc.
};
template <typename T>
class DependentCimg : public virtual SuperCimg, public virtual Cimg<T> {
// expose the needed constructors and methods
public:
Tfloat linear_atX(/* ... */) {
return Cimg<T>::linear_atX(/* ... */);
}
};
但正如你所看到的,实施是乏味的,因为它需要重新定义的所有接口。另外,每种方法最终都会变成虚拟的,这会在运行时产生影响(也许这就是实现者没有成为超类的原因)。
处理这个问题的另一种可能的方式是将你的应用程序的每个算法都作为该类型的多态,并将最依赖的部分切分为特定的类,这些类将用作模板参数给你的算法(有点像分配器,比较器和std库模板的其他可配置部分作为这些模板的参数)。
感谢“madcoder”和“didierc”。我发现你的答案很有用。我最终是这样的:
#include <CImg.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>
using namespace cimg_library;
class cimg_base
{
public:
virtual int load_bmp(const char *const filename) = 0;
virtual int save_bmp (const char *const filename) = 0;
virtual void blur (const float sigma) = 0;
virtual void sharpen (const float amplitude) = 0;
};
class cimg_unsigned_char : public cimg_base
{
CImg <unsigned char> img;
int load_bmp (const char *const filename) { img.load_bmp(filename); return 0;}
int save_bmp (const char *const filename) { img.save_bmp(filename); return 0;}
void blur (const float sigma) { img.blur(sigma); }
void sharpen (const float amplitude) { img.sharpen(amplitude); };
};
class cimg_unsigned_short : public cimg_base
{
CImg <unsigned short> img;
int load_bmp (const char *const filename) { img.load_bmp(filename); return 0;}
int save_bmp (const char *const filename) { img.save_bmp(filename); return 0;}
void blur (const float sigma) { img.blur(sigma); }
void sharpen (const float amplitude) { img.sharpen(amplitude); };
};
void main(void)
{
cimg_base *data;
LARGE_INTEGER lpFrequency;
LARGE_INTEGER lpPerformanceCountStart, lpPerformanceCountEnd;
double Frequency,Start,End;
// no matter witch line is used - progrm work as expected
data = new cimg_unsigned_char;
//data = new cimg_unsigned_short;
data->load_bmp("test.bmp");
//measure time with virtual
QueryPerformanceFrequency(&lpFrequency);
QueryPerformanceCounter(&lpPerformanceCountStart);
data->blur(2.2f);
data->sharpen(2.2f);
QueryPerformanceCounter(&lpPerformanceCountEnd);
Frequency = (double)lpFrequency.QuadPart;
End = (double)lpPerformanceCountEnd.QuadPart;
Start = (double)lpPerformanceCountStart.QuadPart;
printf_s("Time (virtual):%lf ms\n",((End - Start)/Frequency)*1000);
data->save_bmp("output_virt.bmp");
CImg <unsigned char> img;
img.load_bmp("test.bmp");
QueryPerformanceCounter(&lpPerformanceCountStart);
img.blur(2.2f);
img.sharpen(2.2f);
QueryPerformanceCounter(&lpPerformanceCountEnd);
printf_s("Time (normal):%lf ms\n",((End - Start)/Frequency)*1000);
img.save_bmp("output_normal.bmp");
_getch();
}
,因为这个程序的输出是:
Time (virtual):93.705392 ms
Time (normal):93.705392 ms
我不觉得虚函数是我的性能问题(据我所知“didierc”这将是如果我会拨打大量电话,这个问题呢?)。这种解决方案有点“可以接受”吗?或者出于某种原因,我现在不应该这样做?
相关问题:[http://*.com/q/608409/501250](http://*.com/q/608409/501250)。如果您无法使用虚拟基类对CImg '进行翻新,则可能不适用您的情况。 – cdhowie 2013-04-10 19:47:05
在我的网页搜索期间,我找到了这个解决方案。但是我不明白我如何在我的情况下使用它。 (我对C++的了解甚至不足以改变CIMg库中的任何东西......)。所以我唯一的选择是为每种类型创建单独的代码? – user2267612 2013-04-10 19:54:58
不一定。你可以定义你自己的模板函数:'template void do_image_processing(/ * ... * /){CImg img; img.load_raw(/ * ... * /); }' –
cdhowie
2013-04-10 19:56:38