Reputation:
Is there a way to add new methods to a class, without modifying original class definition (i.e. compiled .lib containing class and corresponding .h file) like C#'s class extension methods?
Upvotes: 12
Views: 21078
Reputation: 29
Member functions are usually overrated in C++. With exception of the five or six (as in the rule of five or six) that most of us rarely need, and some operators, everything else should be a free function. Not "friend", just namespace-scoped free function.
If you prefer members because of autocompletion, you can just use appropriate naming (C-style). e.g. for a customer class, a free function can be void customerupdate(customer &, const data&newcustomerdata)
.
Upvotes: 0
Reputation: 82535
No. C++ has no such capability.
As mentioned in other answers, the common workarounds are:
Upvotes: 21
Reputation: 18210
In C++ you can use 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 to 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");
Upvotes: 6
Reputation: 1882
You cannot add methods or data physically to the class file which is in binary form. However, you can add methods and data (functionality and state) to the objects of that class by writing extension classes. This is not straight forward and requires Meta-Object-Protocol and Interface based programming. You need to do a lot to achieve this in C++ since it does not support Reflection out of the box. In such an implementation when you query for the interface implemented by your new extension class via the original class object pointer, the meta object implementation returns that interface pointer via the meta class object for the extension class that it creates at runtime. This is how many customizable (plugin based) software application frameworks work. However, you must remember that it requires many other MOP mechanisms to be written to instanciate meta objects for all the classes using dictionaries in which the object relations are described and give the correct interface pointers for the original and extended class objects. Dassault Systemes' CATIA V5 is written in such an architecture called CAA V5 where you can extend existing components by writing new extension classes with the desired functionality.
Upvotes: 0
Reputation: 15271
Sorry, no. Once your code is in obj, you can not change it. If this can be done in VC partial classes would be supported already. There is one exception though, operator methods can be extended using global functions, pretty like how cout<< is implemented in STL.
Upvotes: -3
Reputation: 247999
There is one way in which it can be done. And that's by relaxing your requirements a bit. In C++, people often say that the interface of a class consists not just of its member functions, but of all functions that work on the class.
That is, non-member functions which can be given the class as a parameter should be considered part of its interface.
For example, std::find()
or std::sort()
are part of the interface of std::vector
, even though they aren't members of the class.
And if you accept this definition, then you can always extend a class simply by adding nonmember functions.
Upvotes: 0
Reputation: 658
Generally not. However, if the library does not create instances of the class that require your extension and you are able to modify all places in the app that create an instance of the class and require your extensions, there is a way you can go:
Example:
class derivedClass: public originalClass { /* ... */};
originalClass* createOriginalClassInstance()
{
return new derivedClass();
}
This is roughly how to implement the "inherit" method suggested by Glen. Glen's "wrapper class with same interface" method is also very nice from a theoretical point of view, but has slightly different properties that makes it less probable to work in your case.
Upvotes: 1
Reputation: 84169
Sure you can:
template <typename Ext>
class Class: public Ext { /* ... */ };
That doesn't mean it's the best approach though.
Upvotes: -3
Reputation: 17258
C# class extension methods are mostly syntactic sugar. You get the same functionality with free functions (i.e., functions with a reference or constant reference to your class as their first parameter). Since this works well for the STL, why not for your class?
Upvotes: 5
Reputation: 22290
No, you can't do this in C++.
If you want to achieve something like this you have 2 options,
I prefer the delegation approach.
Upvotes: 12