C++虚拟模板化方法

MVi*_*tiS 2 c++ polymorphism virtual templates class

我知道这个问题已经一次又一次地以多种不同的形式得到了回答,也许是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();
};
Run Code Online (Sandbox Code Playgroud)

我的想法是将对象链接在一起,就像某个类的一个对象的输出被另一个类的另一个对象直接读取一样.但为了使其工作,所有对象必须能够接受泛型read()函数并返回其所需类型.例如,我有一个类来拼接接受字节(unsigned char)作为输入的位:

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();
};
Run Code Online (Sandbox Code Playgroud)

它返回一个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);
};
Run Code Online (Sandbox Code Playgroud)

现在,让我们假设我想使用FileReader作为数据源创建一个BitExtractor.

BitExtractor bx=BitExtractor(FileReader("SomeFile.abc"));
bool firstBit = bx.read();
Run Code Online (Sandbox Code Playgroud)

在内部,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;
}
Run Code Online (Sandbox Code Playgroud)

尽管它确实编译,但由于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
Run Code Online (Sandbox Code Playgroud)

我已经通过其他StackOverflow问题了解到我的代码在C++中是不可能的,因为它缺乏运行时多态性(编译器无法决定BasicStream子类的哪个模板在运行时调用).我的问题是,鉴于我的数据流/链接模式,还有其他更多的"C++ ish"替代实现我的设计,比如使用或继承STL中的东西(我几乎什么都不知道)?

或者它只是在C++中无法实现?

dav*_*mac 5

问题在于您将模板成员函数声明为virtual:

virtual T read();
Run Code Online (Sandbox Code Playgroud)

......但你没有定义它; 这就是为什么你得到一个链接时错误 - BasicStream<bool>类的vtable 需要一个指向的函数,而没有一个.我很确定可以通过使其成为纯虚拟来解决问题:

virtual T read() = 0;
Run Code Online (Sandbox Code Playgroud)

......或提供默认定义.