Я знаю, что этот вопрос был встречен во многих разных формах снова и снова, и, возможно, это одна из самых запутанных точек в дизайне C++, но я пытаюсь выучить язык через много лет, делая много вещей в чистом C, который считался бы совершенно незаконным в мире C++ (мышление функции указателей жонглирование). Я хочу попытаться воспитывать себя в умении C++, прежде чем сдаваться и перейти на другой язык.C++ virtual templated method
Я только что начал проект, в котором наиболее фундаментальным компонентом является потоковый класс, и для этого я хотел бы, чтобы он был общим: какие данные он будет передавать в соответствии с его подклассами.
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);
};
Теперь, давайте предположим, что я хочу, чтобы создать BitExtractor используя FileReader в качестве источника данных.
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++?
В вашем коде не указан вопрос, о котором вы говорите в своем названии. Базовый класс шаблона может ввести виртуальную функцию (даже такую, которая зависит от параметра типа шаблона класса). Когда вы создаете экземпляр шаблона, в таблице vtable есть только одна четко определенная запись. – StoryTeller
Ваша проблема, вероятно, в коде, который вы не показываете. – StoryTeller
Какая ошибка вы получаете, вероятно, из-за того, что у вас что-то не реализовано. «мой код невозможно в C++, учитывая его отсутствие полиморфизма во время выполнения» !! ?? Кто вам сказал, это ? :) C++ поддерживает как статический, так и временный полиморфизм. – Arunmu