C ++扩展函数?

时间:2011-10-27 20:41:49

标签: c++

是否有像C#中那样的C ++扩展名?

例如在C#中你可以这样做:

public static uint SwapEndian(this uint value)
{
    var tmp = BitConverter.GetBytes(value);
    Array.Reverse(tmp);
    return BitConverter.ToUInt32(tmp, 0);
}

someuint.SwapEndian();

C ++中有类似内容吗?

7 个答案:

答案 0 :(得分:6)

扩展方法(以及“静态类”)存在于C#/ Java语言中,仅仅因为设计者认为(Java方式)OOP是The One True Way并且所有内容都必须是来自类的方法:

这不是C ++的做事方式。在C ++中,您有名称空间,自由函数和Koenig lookup来扩展类的行为:

namespace foo
{
    struct bar { ... };

    void act_on_bar(const bar& b) { ... };
}

...

foo::bar b;
act_on_bar(b); // No need to qualify because of Koenig lookup

我通常认为扩展方法有害。如果你对一个类附加太多的行为,你可能无法捕获该类存在的原因。另外(如“部分类”),它们倾向于使代码与非本地类相关。这很糟糕。

关于你的问题,在C ++中你只需:

template <typename T>
T swap_endian(T x)
{
    union { T value; char bytes[sizeof(T)]; } u;
    u.value = x;

    for (size_t i = 0; i < sizeof(T)/2; i++) 
        swap(u.bytes[i], u.bytes[sizeof(T) - i - 1]);

    return u.value;
}

用法:

swap_endian<std::uint32_t>(42);

或者,如果可以推断出类型:

std::uint64_t x = 42;
std::uint64_t y = swap_endian(x);

答案 1 :(得分:5)

C ++中没有扩展功能。您可以将它们定义为自由函数。

uint SwapEndian(uint value){ ... }

答案 2 :(得分:3)

不是那样的,但你可以编写运算符重载,这些重载可以处理你没有编写的类,它有点像方法扩展(但不适用于命名函数,仅适用于那些避开的运算符)已经被那个类定义了)。经典示例是让您的班级使用cout

class MyClass {
public:
    MyClass(const char* blah) : str(blah) { }

    const char* string() const {
        return str;
    }

private:
    const char* str;
};

// this is kinda like a method extension
ostream& operator<<(ostream& lhs, const MyClass& rhs) {
    lhs << rhs.string();
}

// then you can use it like this
MyClass m("hey ho");
cout << m;

// prints hey ho

这当然是一个微不足道的例子,但你明白了。

答案 3 :(得分:2)

不是以直接类似的方式,但很多时候您可以使用模板实现所需的效果。如果不从原始类派生,就不能在C ++中为具体类“添加”方法,但可以创建适用于任何类型的函数模板。

例如,这是一个函数模板库,用于执行任何整数类型的ntoh类型转换:

template<class Val> inline Val ntohx(const Val& in)
{
    char out[sizeof(in)] = {0};
    for( size_t i = 0; i < sizeof(Val); ++i )
        out[i] = ((char*)&in)[sizeof(Val)-i-1];
    return *(reinterpret_cast<Val*>(out));
}

template<> inline unsigned char ntohx<unsigned char>(const unsigned char & v )
{
    return v;
}
template<> inline uint16_t ntohx<uint16_t>(const uint16_t & v)
{
    return ntohs(v);
}

template<> inline uint32_t ntohx<uint32_t>(const uint32_t & v)
{
    return ntohl(v);
}

template<> inline uint64_t ntohx<uint64_t>(const uint64_t & v)
{
    uint32_t ret [] =
    {
        ntohl(((const uint32_t*)&v)[1]),
        ntohl(((const uint32_t*)&v)[0])
    };
    return *((uint64_t*)&ret[0]);
}
template<> inline float ntohx<float>(const float& v)
{
    uint32_t const* cast = reinterpret_cast<uint32_t const*>(&v);
    uint32_t ret = ntohx(*cast);
    return *(reinterpret_cast<float*>(&ret));
};

答案 4 :(得分:1)

不,对不起,但在C ++中没有类似的东西,它也永远不会。标准有许多依赖于实现的东西(即编译器可以按照它喜欢的方式执行),而且C ++也没有标准化的ABI

答案 5 :(得分:1)

如果您指的是this - 合格的方法参数,那么没有。但根据您的具体用例,可能会有一些其他聪明的技巧......您能提供更多详细信息吗?

答案 6 :(得分:1)

我发现的一种方法是使用重载的“&gt;&gt;”具有lambda表达式的运算符。以下代码演示了这一点。您必须知道使用运算符“&gt;&gt;”而不是“ - &gt;”,这是因为我使用的编译器不允许运算符“ - &gt;”要超载。还因为运营商“&gt;&gt;”优先级低于“ - &gt;”你必须使用括号强制编译器按正确的顺序评估方程式。

最终,它成为您尝试生成的代码的样式,可维护性,可靠性和清洁性的问题。人们会争辩定义“SubtractValue”方法,使用两个参数创建更有效的代码,但其他人会认为重载方法更易于维护。最后,由建筑师和开发人员决定对他们的项目重要的是什么。我只是为这个问题提供了一个可能的解决方案。

#include <functional>
#include <iostream>
#include <stdio.h>
#include <tchar.h>

// Some plain demo class that cannot be changed.
class DemoClass
{
public:
    int GetValue() { return _value; }
    int SetValue(int ivalue) { _value = ivalue; return _value; }
    DemoClass *AddValue(int iadd) { this->_value += iadd; return this; }

private:
    int _value = 0;
};

// Define Lambda expression type that takes and returns a reference to the object.
typedef std::function<DemoClass *(DemoClass *obj)> DemoClassExtension;

// Overload the ">>" operator because we cannot overload "->" to execute the extension.
DemoClass* operator>>(DemoClass *pobj, DemoClassExtension &method)
{
    return method(pobj);
}

// Typical extensions.

// Subtract value "isub".
DemoClassExtension SubtractValue(int isub)
{
    return [=](DemoClass *pobj) {
        pobj->AddValue(-isub);
        return pobj;
    };
}

// Multiply value "imult".
DemoClassExtension MultiplyValue(int imult)
{
    return [=](DemoClass *pobj) {
        pobj->SetValue(pobj->GetValue() * imult);
        return pobj;
    };
}

int _tmain(int argc, _TCHAR* argv[])
{
    DemoClass *pDemoObject = new DemoClass();
    int value = (pDemoObject->AddValue(14) >> SubtractValue(4) >> MultiplyValue(2))->GetValue();
    std::cout << "Value is " << value;
    return 0;
}

以上代码输出为“Value is 20”。