简体   繁体   English

C ++扩展函数?

[英]C++ Extension functions?

Are there extensions for C++ like there are in C#? 是否有像C#中的C ++扩展?

For example in C# you can do: 例如在C#中你可以这样做:

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

someuint.SwapEndian();

Is there anything like that in C++? 在C ++中有类似的东西吗?

Extension methods (and also "static classes") exist in C#/Java languages solely because the designers decided that (the Java way of) OOP is The One True Way and that everything must be a method from a class: 扩展方法(以及“静态类”)只存在于C#/ Java语言中,因为设计者认为(Java方式)OOP是The One True Way,并且所有内容都必须是来自类的方法:

This is not C++ way of doing things. 这不是C ++的做事方式。 In C++ you have namespaces, free functions and Koenig lookup to extend the behavior of a class: 在C ++中,您有名称空间,自由函数和Koenig查找来扩展类的行为:

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

I usually consider extension methods harmful. 我通常认为扩展方法有害。 If you attach too much behavior to a class, you are proabably failing to capture the reason why the class exists. 如果你对一个类附加太多的行为,你可能无法捕获该类存在的原因。 Also (like "partial classes"), they tend to make the code related to a class non local. 另外(如“部分类”),它们倾向于使代码与非本地类相关。 Which is bad. 这很糟糕。

As to your problem, in C++ you simply do: 至于你的问题,在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;
}

Usage: 用法:

swap_endian<std::uint32_t>(42);

or, if the type can be deduced: 或者,如果可以推断出类型:

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

There are no extension functions in C++. C ++中没有扩展函数。 You can just define them as free functions. 您可以将它们定义为自由函数。

uint SwapEndian(uint value){ ... }

Not like that, but you can write operator overloads which work on classes you didn't write, and it's a little like like method extensions (but not for named functions, only for operators that haven't been defined by that class already). 不是那样,但你可以编写运算符重载,这些重载可以处理你没有编写的类,它有点像方法扩展(但不适用于命名函数,只适用于那些尚未被该类定义的运算符)。 The classic example is making your class work with cout : 经典的例子是让你的课程与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

This is a trivial example of course, but you get the idea. 这当然是一个微不足道的例子,但你明白了。

Not in a directly-analogous way, but many times you can achieve the desired effect using templates. 不是以直接类似的方式,但很多时候您可以使用模板实现所需的效果。 You cannot "add" methods to a concrete class in C++ without deriving from the original class, but you can create function templates that work with any type. 如果不从原始类派生,则不能在C ++中将具体类“添加”到具体类,但您可以创建适用于任何类型的函数模板。

For example, here's a function template library I use to do ntoh-type conversions of any integral type: 例如,这是一个函数模板库,用于执行任何整数类型的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));
};

One method I have found is to use the overloaded ">>" operator with lambda expressions. 我发现的一种方法是使用带有lambda表达式的重载“>>”运算符。 The following code demonstrates this. 以下代码演示了这一点。 You have to know to use operator ">>" instead of "->", this is because the compiler I use will not allow the operator "->" to be overloaded. 您必须知道使用运算符“>>”而不是“ - >”,这是因为我使用的编译器不允许运算符“ - >”重载。 Also because the operator ">>" has lower precedence than the "->" you have to use parentheses to force to compiler to evaluate the equation in the correct order. 另外,因为运算符“>>”的优先级低于“ - >”,所以必须使用括号强制编译器按正确的顺序计算等式。

In the end it becomes a matter of style, maintainability, reliability and cleanness of the code you are trying to produce. 最终,它成为您尝试生成的代码的样式,可维护性,可靠性和清洁性的问题。 One would argue defining the "SubtractValue" method with two arguments creates more efficient code, but others would argue the overloaded method is more maintainable. 人们会争辩定义“SubtractValue”方法,使用两个参数创建更有效的代码,但其他人会认为重载方法更易于维护。 In the end it is left to the architects and developers to determine what is important to their project. 最后,由建筑师和开发人员决定对他们的项目重要的是什么。 I am just providing a possible solution to the issue. 我只是提供了一个可能的问题解决方案。

#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;
}

The above code output is "Value is 20". 上面的代码输出是“Value is 20”。

No, sorry, but there's nothing like that in C++ and it can also never be. 不,对不起,但在C ++中没有类似的东西,它也永远不会。 There are lots of things that the standard leaves as implementation-dependent (ie the compiler can do it any way it prefers), and also C++ does not have a standardized ABI . 标准留下了许多依赖于实现的东西(即编译器可以以任何方式执行它),并且C ++也没有标准化的ABI

If you're referring to the this -qualified method parameter, then no. 如果你指的是this合格的方法参数,那么没有。 But there may be some other clever tricks depending on your specific use case... Can you provide more detail? 但根据您的具体用例,可能会有一些其他聪明的技巧......您能提供更多细节吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM