我知道这个问题已经以许多不同的形式一再回答,并且也许是C++设计中最令人困惑的要点之一,但是我试图在多年以来用纯C语言做很多事情之后学习这种语言。在C++世界中是非常违法的(请考虑使用函数指针)。在放弃并使用另一种语言之前,我想尝试对C++的思维方式进行自我教育。
我刚刚启动了一个项目,其中最基本的组成部分是流类,为此,我希望它是通用的:它将流哪种类型的数据取决于其子类。
template <typename T>
class BasicStream {
protected:
T *buffer;
unsigned int bufferSize;
unsigned int bufferPos;
bool streamEnd=false;
public:
virtual T read();
};
我的想法是将对象链接在一起,就像某个类的一个对象的输出被另一类的另一个对象直接读取一样。但是,要使此方法起作用,所有对象都必须能够接受通用的
read()
函数并返回其所需的类型。例如,我有一个用于拼接位的类,该位接受字节(无符号字符)作为输入:class BitExtractor : public BasicStream<bool> {
private:
unsigned char bitMask;
unsigned char byte;
BasicStream<unsigned char> &byteSource;
public:
BitExtractor(BasicStream<unsigned char> &source);
virtual bool read();
};
它返回
bool
类型,并且需要从BasicStream
派生并且具有<unsigned char>
返回类型的任何类作为输入。我的想法是使输入与数据源完全无关。是文件,互联网流,甚至是内存中的某个位置;全部包裹在从BasicStream<unsigned char>
派生的类周围。一个示例是
FileReader
类,用于处理同步文件加载:class FileReader : public BasicStream<unsigned char> {
protected:
FILE *file;
bool asyncFlag;
bool asyncOpReady;
bool fileEnded;
pthread_t asyncThread;
unsigned int lastRead;
public:
FileReader(char *fileName,int bufferSize=1024,bool asyncRead=false);
~FileReader();
virtual unsigned char read();
private:
typedef struct {
unsigned int amount;
unsigned int *read;
unsigned char *buffer;
FILE *file;
bool *flag;
bool *flagStreamEnd;
} TData;
static void AsyncRead(void *data);
};
现在,假设我想使用FileReader作为数据源创建一个BitExtractor。
BitExtractor bx=BitExtractor(FileReader("SomeFile.abc"));
bool firstBit = bx.read();
在内部,
BitExtractor
调用FileReader的read()
方法。我的假设是,由于FileReader
是派生自BasicStream<unsigned char>
的类,因此它应该识别模板化函数。BitExtractor::BitExtractor(BasicStream<UInt8> &source):bitMask(128),byteSource(source){}
bool BitExtractor::read(){
bool bit=byte&bitMask;
if(streamEnd==false){
bitMask>>=1;
if(bitMask==0){
try {
byte=byteSource.read();
bitMask=128;
} catch (...) {
streamEnd=true;
}
}
}
else{
throw "Bytesource has ended!\n";
}
return bit;
}
即使可以编译,但由于
vtable
错误而无法链接:Undefined symbols for architecture x86_64:
"BasicStream<bool>::read()", referenced from:
vtable for BasicStream<bool> in BitIO.o
"BasicStream<unsigned char>::read()", referenced from:
vtable for BasicStream<unsigned char> in FileIO.o
尽管存在其他StackOverflow问题,但我已经了解到,由于缺乏运行时多态性,我的代码在C++中是不可能的(编译器无法确定子类在运行时调用哪个
BasicStream
模板)。我的问题是,考虑到我的数据流/链接模式,是否还有其他“C++ ish”替代方法来实现我的设计,例如使用或继承STL中的某些内容(我几乎一无所知)?还是在C++中根本无法实现?
最佳答案
目前的问题是您声明模板成员函数为virtual:
virtual T read();
...但是您没有定义它;这就是为什么会出现链接时错误的原因-
BasicStream<bool>
类的vtable需要指向一个函数,而没有一个函数。我很确定可以通过将其变为纯虚拟来解决该问题:virtual T read() = 0;
...或提供默认定义。