我正在编写一个C++库,它将对文件、内存缓冲区和使用HTTP访问的远程文件进行交互。
为了处理这个问题,我决定创建一些使用以下接口的类:
class DataStreamInterface {
public:
virtual bool open() = 0;
virtual void close() = 0;
virtual std::streamsize length() const = 0;
virtual std::streamsize tell() const = 0;
virtual std::streamsize seek(std::streamsize position) = 0;
virtual std::streamsize read(char *buffer,
std::streamsize length) = 0;
virtual std::streamsize read(int8_t *buffer) = 0;
virtual std::streamsize read(uint8_t *buffer) = 0;
virtual std::streamsize read(int16_t *buffer) = 0;
virtual std::streamsize read(uint16_t *buffer) = 0;
virtual std::streamsize read(int32_t *buffer) = 0;
virtual std::streamsize read(uint32_t *buffer) = 0;
virtual std::streamsize read(float *buffer) = 0;
virtual std::streamsize read(double *buffer) = 0;
virtual std::streamsize read(std::string *buffer) = 0;
virtual std::streamsize peek(uint8_t *buffer,
std::streamsize length) = 0;
virtual std::streamsize peek(int8_t *buffer) = 0;
virtual std::streamsize peek(uint8_t *buffer) = 0;
virtual std::streamsize peek(int16_t *buffer) = 0;
virtual std::streamsize peek(uint16_t *buffer) = 0;
virtual std::streamsize peek(int32_t *buffer) = 0;
virtual std::streamsize peek(uint32_t *buffer) = 0;
virtual std::streamsize peek(float *buffer) = 0;
virtual std::streamsize peek(double *buffer) = 0;
virtual std::streamsize peek(std::string *buffer) = 0;
virtual std::streamsize write(const char *buffer,
std::streamsize length) = 0;
virtual std::streamsize write(int8_t value) = 0;
virtual std::streamsize write(uint8_t value) = 0;
virtual std::streamsize write(int16_t value) = 0;
virtual std::streamsize write(uint16_t value) = 0;
virtual std::streamsize write(int32_t value) = 0;
virtual std::streamsize write(uint32_t value) = 0;
virtual std::streamsize write(float value) = 0;
virtual std::streamsize write(double value) = 0;
virtual std::streamsize write(const std::string &value) = 0;
virtual ~DataStreamInterface() { }
};然后,我创建了用于在MemoryDataStream d缓冲区中读写的malloc、用于读写文件的FileDataStream和用于读取远程文件的HttpDataStream。
MemoryDataStream::MemoryDataStream(const DataStreamInit &dsInit) :
_bigEndian(dsInit.bigEndian) {
}
MemoryDataStream::~MemoryDataStream() {
this->_buffer.clear();
}
bool MemoryDataStream::open() {
return true;
}
void MemoryDataStream::close() {
}
std::streamsize MemoryDataStream::length() const {
return this->_buffer.size();
}
std::streamsize MemoryDataStream::seek(std::streamsize position) {
if (position < 0 ||
static_cast<std::streamsize>(this->_cursor) +
position > this->_buffer.size()) {
return -1;
}
this->_cursor = position;
return this->_cursor;
}
std::streamsize MemoryDataStream::tell() const {
return this->_cursor;
}
std::streamsize MemoryDataStream::read(char *buffer,
std::streamsize length) {
std::streamsize result = 0;
for (int i = 0; i < length; i++) {
result += this->_read(buffer++);
}
return result;
}
std::streamsize MemoryDataStream::read(int8_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(uint8_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(int16_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(uint16_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(int32_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(uint32_t *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(float *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(double *buffer) {
return this->_read(buffer);
}
std::streamsize MemoryDataStream::read(std::string *buffer) {
std::streamsize i;
std::string result;
i = this->peek(&result);
if (i < 1) {
return i;
}
*buffer = result;
this->_cursor += i;
return i;
}
template <typename T>
std::streamsize MemoryDataStream::_read(T *buffer) {
std::streamsize result = this->_peek(buffer);
if (result > 0) {
this->_cursor += result;
}
return result;
}
std::streamsize MemoryDataStream::peek(uint8_t *buffer,
std::streamsize length) {
std::streamsize result = 0;
for (int i = 0; i < length; i++) {
result += this->_peek(buffer++);
}
return result;
}
std::streamsize MemoryDataStream::peek(int8_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(uint8_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(int16_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(uint16_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(int32_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(uint32_t *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(float *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(double *buffer) {
return this->_peek(buffer);
}
std::streamsize MemoryDataStream::peek(std::string *value) {
int8_t c;
std::streamsize i;
int size;
std::stringstream strm;
for (i = 0; i < 32768; ++i) {
if (this->_peek(&c) < 1 || c == '\0') {
break;
} else {
this->_cursor += 1;
}
size = i;
strm << c;
}
*value = strm.str();
this->_cursor -= size;
return i;
}
template <typename T>
std::streamsize MemoryDataStream::_peek(T *buffer) {
T value;
T finalValue;
uint8_t *originalData;
uint8_t *finalData;
std::streamsize size = static_cast<std::streamsize>(sizeof(T));
if (static_cast<std::streamsize>(this->_cursor) +
size > this->_buffer.size()) {
return -1;
}
value = *(reinterpret_cast<T*>(&this->_buffer[this->_cursor]));
if (_bigEndian && sizeof(T) > 1) {
originalData = reinterpret_cast<uint8_t*>(&value);
finalData = reinterpret_cast<uint8_t*>(&finalValue);
for (int i = 0; i < sizeof(T); ++i) {
finalData[i] = originalData[(sizeof(T) - i) - 1];
}
value = finalValue;
}
*buffer = value;
return sizeof(T);
}
std::streamsize MemoryDataStream::write(const char *buffer,
std::streamsize length) {
return this->_write(buffer, length);
}
std::streamsize MemoryDataStream::write(int8_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(uint8_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(int16_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(uint16_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(int32_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(uint32_t value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(float value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(double value) {
return this->_write(value);
}
std::streamsize MemoryDataStream::write(const std::string &value) {
return this->_write(value.c_str(), strlen(value.c_str()) + 1);
}
template <typename T>
std::streamsize MemoryDataStream::_write(T buffer,
std::streamsize length) {
size_t pos = static_cast<size_t>(this->_cursor);
size_t size = static_cast<size_t>(length);
if (pos + size > this->_buffer.size()) {
this->_buffer.resize(pos + size);
}
memcpy(&this->_buffer[pos], static_cast<T>(buffer), size);
this->_cursor += size;
return size;
}
template <typename T>
std::streamsize MemoryDataStream::_write(T value) {
T finalValue = value;
uint8_t *originalData = reinterpret_cast<uint8_t*>(&value);
uint8_t *finalData = reinterpret_cast<uint8_t*>(&finalValue);
if (_bigEndian && sizeof(T) > 1) {
for (int i = 0; i < sizeof(T); ++i) {
finalData[i] = originalData[(sizeof(T) - i) - 1];
}
originalData = finalData;
}
return this->_write(originalData, sizeof(T));
}我想提出以下问题:
让DataStreamInterface成为抽象类而不是接口,这样我就可以像这样使用模板了吗?它会影响性能或内存消耗吗?
std::streamsize read(T *buffer);
std::streamsize peek(T *buffer);
std::streamsize write(T value);我最近意识到,任何安卓和iOS应用程序在使用自己的DataStream实现库时都会冻结。
例如,如果"C++ side“调用用Java实现的HttpDataStream类来下载文件,它将冻结整个过程,甚至整个应用程序,直到下载结束。
下面是一个例子,调用在Java中定义的远程DataStream类:
std::streamsize DataStreamJava::read(double value) {
jmethodID m = jni->GetMethodID(j_dataStream_class_,
"read", "(D)J");
jni->CallLongMethod(j_dataStream_global_, m);
return 0;
}我一直在考虑在“DataStreamObserver端”上创建一个名为C++的类,DataStream构造函数将接受DataStreamObserver类的一个实例,然后每次完成读或写操作时都调用它。
我是否应该将DataStreamObserver作为一个带有模板的抽象类来创建,以避免实现这样的方法?
virtual void onReadSuccess(int8_t value, std::steamsize length) = 0;
virtual void onReadSuccess(uint8_t value, std::steamsize length) = 0;
virtual void onReadSuccess(int16_t value, std::steamsize length) = 0;
virtual void onReadSuccess(uint16_t value, std::steamsize length) = 0;发布于 2015-08-01 02:05:29
似乎所有这些方法都不应该是虚拟的。
class DataStreamInterface {
public:
virtual bool open() = 0;
virtual void close() = 0;
virtual std::streamsize length() const = 0;
virtual std::streamsize tell() const = 0;
virtual std::streamsize seek(std::streamsize position) = 0;
virtual std::streamsize read(char *buffer,
std::streamsize length) = 0;
virtual std::streamsize read(int8_t *buffer) = 0;
virtual std::streamsize read(uint8_t *buffer) = 0;
virtual std::streamsize read(int16_t *buffer) = 0;
virtual std::streamsize read(uint16_t *buffer) = 0;
virtual std::streamsize read(int32_t *buffer) = 0;
virtual std::streamsize read(uint32_t *buffer) = 0;
virtual std::streamsize read(float *buffer) = 0;
virtual std::streamsize read(double *buffer) = 0;
virtual std::streamsize read(std::string *buffer) = 0;
virtual std::streamsize peek(uint8_t *buffer,
std::streamsize length) = 0;
virtual std::streamsize peek(int8_t *buffer) = 0;
virtual std::streamsize peek(uint8_t *buffer) = 0;
virtual std::streamsize peek(int16_t *buffer) = 0;
virtual std::streamsize peek(uint16_t *buffer) = 0;
virtual std::streamsize peek(int32_t *buffer) = 0;
virtual std::streamsize peek(uint32_t *buffer) = 0;
virtual std::streamsize peek(float *buffer) = 0;
virtual std::streamsize peek(double *buffer) = 0;
virtual std::streamsize peek(std::string *buffer) = 0;
virtual std::streamsize write(const char *buffer,
std::streamsize length) = 0;
virtual std::streamsize write(int8_t value) = 0;
virtual std::streamsize write(uint8_t value) = 0;
virtual std::streamsize write(int16_t value) = 0;
virtual std::streamsize write(uint16_t value) = 0;
virtual std::streamsize write(int32_t value) = 0;
virtual std::streamsize write(uint32_t value) = 0;
virtual std::streamsize write(float value) = 0;
virtual std::streamsize write(double value) = 0;
virtual std::streamsize write(const std::string &value) = 0;
virtual ~DataStreamInterface() { }
};在您的实现中,添加了执行实际工作的_write()、_read()和_peek()。似乎这些都是您的虚拟函数,其他的应该在基类DataStreamInterface中实现,以使用这些虚拟函数。
我想我会这样实施:
class DataStreamInterface {
public:
// Virtual Interface:
virtual ~DataStreamInterface() { }
virtual bool open() = 0;
virtual void close() = 0;
virtual std::streamsize length() const = 0;
virtual std::streamsize tell() const = 0;
virtual std::streamsize seek(std::streamsize position) = 0;
private:
// All the interesting stuff for each class is encapsulated in
// these threee virtual methods. All the other read/peek/write
// methods should delagate their work to these and not need to
// be re-implemented in each class.
virtual std::streamsize vread(char *buffer, std::size_t size) = 0;
virtual std::streamsize vwrite(char *buffer, std::size_t size) = 0;
virtual std::streamsize vpeek(char *buffer, std::size_t size) = 0;
template<typename T>
std::streamsize tread(T *buffer, std::size_t size = sizeof(T))
{
return vread(reinterpret_cast<char*>(buffer), size);
}
template<typename T>
std::streamsize twrite(T *buffer, std::size_t size = sizeof(T))
{
return vwrite(reinterpret_cast<char*>(buffer), size);
}
template<typename T>
std::streamsize tpeek(T *buffer, std::size_t size = sizeof(T))
{
return vpeak(reinterpret_cast<char*>(buffer), size);
}
// standard interface.
// I did these in a hurry there will be mistakes.
public:
std::streamsize read(char *buffer, std::streamsize length){return tread(buffer, length);}
std::streamsize read(int8_t *buffer) {return tread(buffer);}
std::streamsize read(uint8_t *buffer) {return tread(buffer);}
std::streamsize read(int16_t *buffer) {return tread(buffer);}
std::streamsize read(uint16_t *buffer) {return tread(buffer);}
std::streamsize read(int32_t *buffer) {return tread(buffer);}
std::streamsize read(uint32_t *buffer) {return tread(buffer);}
std::streamsize read(float *buffer) {return tread(buffer);}
std::streamsize read(double *buffer) {return tread(buffer);}
std::streamsize read(std::string *buffer) {return tread(buffer);}
std::streamsize peek(uint8_t *buffer, std::streamsize length) {return tpeek(buffer, length);}
std::streamsize peek(int8_t *buffer) {return tpeek(buffer);}
std::streamsize peek(uint8_t *buffer) {return tpeek(buffer);}
std::streamsize peek(int16_t *buffer) {return tpeek(buffer);}
std::streamsize peek(uint16_t *buffer) {return tpeek(buffer);}
std::streamsize peek(int32_t *buffer) {return tpeek(buffer);}
std::streamsize peek(uint32_t *buffer) {return tpeek(buffer);}
std::streamsize peek(float *buffer) {return tpeek(buffer);}
std::streamsize peek(double *buffer) {return tpeek(buffer);}
std::streamsize peek(std::string *buffer) {return tpeek(buffer.c_str(), buffer->length());}
std::streamsize write(const char *buffer,std::streamsize length) {return tpeek(buffer, length);}
std::streamsize write(int8_t value) {return twrite(buffer);}
std::streamsize write(uint8_t value) {return twrite(buffer);}
std::streamsize write(int16_t value) {return twrite(buffer);}
std::streamsize write(uint16_t value) {return twrite(buffer);}
std::streamsize write(int32_t value) {return twrite(buffer);}
std::streamsize write(uint32_t value) {return twrite(buffer);}
std::streamsize write(float value) {return twrite(buffer);}
std::streamsize write(double value) {return twrite(buffer);}
std::streamsize write(const std::string &value) {return twrite(buffer.c_str(), value.size());}
};让DataStreamInterface成为抽象类而不是接口,这样我就可以像这样使用模板了吗?
抽象类是一个接口。不同之处在于术语。
它会影响性能或内存消耗吗?
好的。但不是以任何有意义的方式。但在我给出更准确的答案之前,我需要你说得更具体些。
例如,如果"C++ side“调用用Java实现的HttpDataStream类来下载文件,它将冻结整个过程,甚至整个应用程序,直到下载结束。
一点都不奇怪。但这与它是一个C++函数无关。如果你要求处理器做一些事情,它不能做任何事情直到它完成。所以它会结冰。
除非您显式地将代码线程化,并在不同的线程上执行一些工作。
我一直在考虑在“DataStreamObserver端”上创建一个名为C++的类,DataStream构造函数将接受DataStreamObserver类的一个实例,然后每次完成读或写操作时都调用它。
好的。但这本身并不能帮助你的拖延过程。
发布于 2015-08-02 13:18:22
如果您不想处理基于任何原因的虚拟函数,CRTP也可以是另一种设计。
template<typename T>
class DataStreamInterface
{
public:
void read(double* buffer)
{
static_cast<T*>(this)->StreamRead(buffer, sizeof(double));
}
void write(double* buffer)
{
static_cast<T*>(this)->StreamWrite(buffer, sizeof(double));
}
};
class Stream : public DataStreamInterface<Stream>
{
public:
void StreamWrite(void* buffer, std::size_t size) {}
void StreamRead(void* buffer, std::size_t size){}
};https://codereview.stackexchange.com/questions/98694
复制相似问题