C++虚拟模板方法

标签 c++ class templates polymorphism virtual

我知道这个问题已经以许多不同的形式一次又一次地得到回答,并且可能是 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()函数并返回其所需的类型。例如,我有一个拼接位的类,它接受字节(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();
};

它返回一个 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++ 风格”的替代方案来实现我的设计,例如使用或子类化来自 STL 的某些东西(我几乎一无所知)?

或者它在 C++ 中根本无法实现?

最佳答案

目前的问题是您将模板成员函数声明为virtual:

virtual T read();

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

virtual T read() = 0;

...或提供默认定义。

关于C++虚拟模板方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37529777/

相关文章:

c++ - "Ignore specific library"在 Visual Studio 中的影响

c++ - 将 STL unicode 字符串转换为 wxString 给出空字符串

java - 使用方法为对象分配其自身的修改版本 - 不好的做法?

c++ - 如何在可变参数模板中获取嵌套参数包?

C++ 特化一个 vector 的成员函数

c++ - 模板类,友元运算符 << 重载

C++ exp LUT(查找表)

c++ - 找不到匹配项

python - 在 python 中调用 int 的 __init__ 看似微不足道的问题

c++ - 如何在 B 类中定义 A 类的对象