从 std::vector 的函数创建自定义扩展

Create Custom Extention from Function for std::vector

我正在尝试学习一些来自 C# 的 C++。我在 C# 中喜欢的一件事是像 CustomItem.ToString() 这样的扩展,并且很好奇我如何在 C++ 中实现类似的东西。我正在使用 std::vector<unsigned char> 来存储缓冲区,然后逐字节处理它。

我有以下功能:

int DataParser::ToLittleEndianInt(std::vector<unsigned char> ba) //Little Endian
{
    long int Int = 0;
    int arraySize = ba.size();
    if (arraySize ==4)
    {
        Int = ba[0] | ((int)ba[1] << 8) | ((int)ba[2] << 16) | ((int)ba[3] << 24);
    }
    else if (arraySize == 2)
    {
        Int = ba[0] | ((int)ba[1] << 8);
    }
    else if (arraySize == 1)
    {
        Int = ba[0];
    }
    return Int;
}

在这里,我可以向它发送一个从 1 到 4 字节的向量,它会为我转换为整数。有没有办法让我像这样使用它:

std::vector<unsigned char> CurrentBytes(4);
for (int i = 0; i < 4; i++)
    CurrentBytes[i]=1;

// how can we do this?
int results = CurrentBytes.ToLittleEndianInt();
//or
int results = CurrentBytes->ToLittleEndianInt();

我只是觉得它的可读性很好,希望对字符串、日期、int、美元等进行扩展。

更新:

我尝试按照建议进行自定义 class,但出现编译时错误。我把它放在我的 .h 文件中:

class Byte
{
    public:
        Byte();
        ~Byte();
        std::string  DataType;
        int  ColumnWidth;
        std::vector<unsigned char> data;
        int ToLEInt() {
            long int Int = 0;
            int arraySize = this->ColumnWidth;
            if (arraySize == 2)
            {
                Int = this->data[0] | ((int)this->data[1] << 8);
            }
            else if (arraySize == 1)
            {
                Int = this->data[0];
            }
            return Int;
        };
};

抛出错误:

Error   LNK2019 unresolved external symbol "public: __thiscall Byte::Byte(void)" (??0Byte@@QAE@XZ) referenced in function "public: static void __cdecl DataParser::Parse(class nlohmann::basic_json<class std::map,class std::vector,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool,__int64,unsigned __int64,double,class std::allocator,struct nlohmann::adl_serializer>)" (?ParseToDataTable@Parse@@SAXV?$basic_json@Vmap@std@@Vvector@2@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@_N_J_KNVallocator@2@Uadl_serializer@nlohmann@@@nlohmann@@@Z)    

我也尝试将其声明为:

const Byte& ToLEInt(const Byte& s)const {}

这是我在 Stephen Prata 的 C++ Primer 中看到的方法,但我仍然会出错,我必须在我的 cpp 中像这样使用它:

std::vector<unsigned char> test(3);
for (int i = 0; i < 2; i++)
        test[i] = i;
    Byte CurrentBytes;
    CurrentBytes.data = test;
    CurrentBytes.ColumnWidth=2;
    int results = CurrentBytes.ToLEInt(CurrentBytes);
    //instead of
    int results = CurrentBytes.ToLEInt();

然后我尝试将声明放在 class 块之外,但随后我收到一个错误,指出 LEInt 未定义,

int Byte::ToLEInt(){}

当我尝试将 int ToLEInt(); 添加到 class 块时,它会抱怨说它已经被定义了。

unresolved external symbol "public: __thiscall Byte::Byte(void)... 错误意味着链接器程序无法找到您的 class Byte 的构造函数的定义(主体)。为了解决这个问题,您可以在构造函数和析构函数声明中添加空括号(这次没有分号),如下所示:

class Byte
{
    public:
        Byte() {}
        ~Byte() {}
        ...

或者完全删除它们的声明,因为目前它们仍然处于空闲状态:

class Byte
{
    public:
        //Byte();  - can be removed entirely
        //~Byte(); - can be removed entirely
        ...

当您不提供构造函数时,编译器会隐式生成默认构造函数,因此您不必担心它的声明或定义(正文)。但是,当您声明一个时,您需要自己提供它的定义(至少是空括号)。

// how can we do this?
int results = CurrentBytes.ToLittleEndianInt();
//or
int results = CurrentBytes->ToLittleEndianInt();

你不能。 C++ 不是那样工作的。

你可以做的是:

// assuming DataParser is a namespace
using namespace DataParser;
int results = ToLittleEndianInt(CurrentBytes);
// or...
int results = DataParser::ToLittleEndianInt(CurrentBytes); 

这是 C++ 的处理方式。

如果你想要一个更优雅的解决方案,你可以从 std::vector 继承,尽管 this is not recommended.

更好的方法是创建自己的 class:

class myContainer {
    private:
        std::vector data;
    public:
        //...
        int ToLittleEndianInt() {
            // Process data...
            return result;
        }
};

那么您的代码将变为:

myContainer CurrentBytez;
//...
int results = CurrentBytes.ToLittleEndianInt();

当然,创建您自己的 class 需要一些研究,尤其是 C++ 与 C# 中的 classes 有何不同,但这可能是值得的。无论如何你可能想学习它,所以这没什么大不了的。