[ACCEPTED]-C++ Class Extension-extension-methods
No. C++ has no such capability.
As mentioned 2 in other answers, the common workarounds 1 are:
- Define a derived class, perhaps with a factory to hide the actual implementation class
- Define a decorator class
- Define non-member functions that operate on instances of the class
No, you can't do this in C++.
If you want 2 to achieve something like this you have 1 2 options,
- You could inherit from the class (if this is an option, it might not be legal as the class may not have been written to allow inheritance)
- You can write your own wrapper class that has the same interface + your new methods and delegate to the one you want to extend.
I prefer the delegation approach.
C# class extension methods are mostly syntactic 5 sugar. You get the same functionality with 4 free functions (i.e., functions with a reference 3 or constant reference to your class as their 2 first parameter). Since this works well 1 for the STL, why not for your class?
In C++ you can use free functions, but sometimes 27 extension methods work better when you nest 26 many functions together. Take a look at 25 this C# code:
var r = numbers.Where(x => x > 2).Select(x => x * x);
If we to write this in C++ using 24 free function it would look like this:
auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });
Not 23 only is this difficult to read, but it is 22 difficult to write. The common way to solve 21 this is to create what is called a pipable 20 function. These functions are created by 19 overloading the |
pipe operator(which is 18 just really the or operator). So the code 17 above could be written like this:
auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });
Which is 16 much easier to read and write. Many libraries 15 use pipable function for ranges, but it 14 could be expanded to other classes as well. Boost 13 uses it in their range library, pstade oven uses 12 it, and also this C++ linq library uses it as 11 well.
If you would like to write your own 10 pipable function, boost explain how to do 9 that here. Other libraries, however, provide 8 function adaptors to make it easier. Pstade 7 egg has a pipable adaptor, and linq provides the range_extension
adaptor 6 to create a pipable function for ranges 5 as least.
Using linq, you first just create 4 your function as a function object like 3 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 2 static initialization like this:
range_extension<contains_t> contains = {};
Then you 1 can use your pipable function like this:
if (numbers | contains(5)) printf("We have a 5");
Generally not. However, if the library does 11 not create instances of the class that require 10 your extension and you are able to modify 9 all places in the app that create an instance 8 of the class and require your extensions, there 7 is a way you can go:
- Create a factory function that is called at all places that require an instance of the class and returns a pointer to the instance (google for Design Patterns Factory, ...).
- Create a derived class with the extensions you want.
- Make the factory function return your derived class instead of the original class.
Example:
class derivedClass: public originalClass { /* ... */};
originalClass* createOriginalClassInstance()
{
return new derivedClass();
}
- Whenever you need to access the extensions, you need to cast the original cast to the derived class, of course.
This is roughly 6 how to implement the "inherit" method suggested 5 by Glen. Glen's "wrapper class with same 4 interface" method is also very nice from 3 a theoretical point of view, but has slightly 2 different properties that makes it less 1 probable to work in your case.
There is one way in which it can be done. And 11 that's by relaxing your requirements a bit. In 10 C++, people often say that the interface 9 of a class consists not just of its member 8 functions, but of all functions that work on the class.
That is, non-member functions 7 which can be given the class as a parameter 6 should be considered part of its interface.
For 5 example, std::find()
or std::sort()
are part of the interface 4 of std::vector
, even though they aren't members of 3 the class.
And if you accept this definition, then 2 you can always extend a class simply by 1 adding nonmember functions.
You cannot add methods or data physically 27 to the class file which is in binary form. However, you 26 can add methods and data (functionality 25 and state) to the objects of that class 24 by writing extension classes. This is not 23 straight forward and requires Meta-Object-Protocol 22 and Interface based programming. You need 21 to do a lot to achieve this in C++ since 20 it does not support Reflection out of the 19 box. In such an implementation when you 18 query for the interface implemented by your 17 new extension class via the original class 16 object pointer, the meta object implementation 15 returns that interface pointer via the meta 14 class object for the extension class that 13 it creates at runtime. This is how many 12 customizable (plugin based) software application 11 frameworks work. However, you must remember 10 that it requires many other MOP mechanisms 9 to be written to instanciate meta objects 8 for all the classes using dictionaries in 7 which the object relations are described 6 and give the correct interface pointers 5 for the original and extended class objects. Dassault 4 Systemes' CATIA V5 is written in such an 3 architecture called CAA V5 where you can 2 extend existing components by writing new 1 extension classes with the desired functionality.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.