Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C or C++, is there a way to extend a class without inheritance?

Is there a way to implement functionality like Class Categories (of Objective-C) or Extension Methods (of C# 3.0) in C and/or C++?

like image 542
paul simmons Avatar asked May 28 '10 01:05

paul simmons


2 Answers

C++ has free functions, but sometimes extension methods work better when you nest many functions together. Take a look at this C# code:

var r = numbers.Where(x => x > 2).Select(x => x * x);

If we write this in C++ using free function it would look like this:

auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });

Not only is this difficult to read, but it is difficult to write. The common way to solve this is to create what is called a pipable function. These functions are created by overloading the | pipe operator(which is just really the or operator). So the code above could be written like this:

auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });

Which is much easier to read and write. Many libraries use pipable function for ranges, but it could be expanded to other classes as well. Boost uses it in their range library, pstade oven uses it, and also this C++ linq library uses it as well.

If you would like to write your own pipable function, boost explain how to do that here. Other libraries, however, provide function adaptors to make it easier. Pstade egg has a pipable adaptor, and linq provides the range_extension adaptor to create a pipable function for ranges as least.

Using linq, you first just create your function as a function object like this:

struct contains_t
{
    template<class Range, class T>
    bool operator()(Range && r, T && x) const
    { return (r | linq::find(x)) != boost::end(r); };
};

Then you initialize the function using static initialization like this:

range_extension<contains_t> contains = {};

Then you can use your pipable function like this:

if (numbers | contains(5)) printf("We have a 5");
like image 144
Paul Fultz II Avatar answered Sep 19 '22 10:09

Paul Fultz II


Not really. It's not the C++ way to treat classes like this.

Amongst others, Meyers argue that it's best to have a small class with the minimal set of operations that make it fully useful. If you want to expand the feature set, you may add an utility namespace (e.g. namespace ClassUtil) that contains non-member utility functions that operate on that minimal class. It's easy to add functions to a namespace from anywhere.

You can check a discussion on the subject here.

like image 37
Johan Kotlinski Avatar answered Sep 19 '22 10:09

Johan Kotlinski