123
123

Reputation: 5824

C++ Extension functions?

Are there extensions for C++ like there are in C#?

For example in C# you can do:

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++?

Upvotes: 20

Views: 11767

Answers (7)

John Dibling
John Dibling

Reputation: 101456

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.

For example, here's a function template library I use to do ntoh-type conversions of any integral type:

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

Upvotes: 2

Michael Erickson
Michael Erickson

Reputation: 4445

One method I have found is to use the overloaded ">>" operator with lambda expressions. 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. 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".

Upvotes: 5

Alexandre C.
Alexandre C.

Reputation: 56956

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:

This is not C++ way of doing things. In C++ you have namespaces, free functions and Koenig lookup to extend the behavior of a class:

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:

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);

Upvotes: 6

Seth Carnegie
Seth Carnegie

Reputation: 75130

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:

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.

Upvotes: 3

mergeconflict
mergeconflict

Reputation: 8276

If you're referring to the this-qualified method parameter, then no. But there may be some other clever tricks depending on your specific use case... Can you provide more detail?

Upvotes: 1

K-ballo
K-ballo

Reputation: 81349

There are no extension functions in C++. You can just define them as free functions.

uint SwapEndian(uint value){ ... }

Upvotes: 8

Jon
Jon

Reputation: 437386

No, sorry, but there's nothing like that in C++ and it can also never be. There are lots of things that the standard leaves as implementation-dependent (i.e. the compiler can do it any way it prefers), and also C++ does not have a standardized ABI.

Upvotes: 0

Related Questions