Distribution as member of class in C++ - c++

I have two related questions concerning the use of distributions inside classes.
Is there some kind of base distribution in C++ in order to use a distribution as a class member without knowing which distribution it will be? I cannot use templates (see question 2)
class Foo{
private:
// could by any distribution
std::base_distribution dist_;
};
I have another class Bar that should have a vector of Foo as a private member (std::vector<Foo>). The problem is that if Foo uses templates, then it is not possible to have a vector of different template arguments which is exactly what I want to have.
class Bar {
private:
std::vector<Foo> foo_;
};
boost::variant doesn't help either because I don't know the type of distributions. So this (for example) is not possible in my case:
class Bar{
private:
boost::variant<std::normal_distribution<>, std::uniform_real_distribution<> > dists_;
};

No, there are no base classes shared by all distribution templates. Even if there were, your intended approach wouldn't work anyway because of object slicing.
However, it should be fairly easy to create your own base class, and derive from it.
class base_distribution {};
template<typename ...Args> class normal_distribution :
public base_distribution, public std::normal_distribution<Args...> {};
template<typename ...Args> class uniform_int_distribution :
public base_distribution, public std::inform_int_distribution<Args...> {};
... and so on, for whatever distributions you want to support. You will also probably need to delegate the wrappers' constructors to their real distribution base class, for maximum transparency.
At this point, object slicing becomes a factor, so you can't just shove a base_distribution into a class, as a member, or shove it into a vector, and expect it to work. You'll have to use, at very least a
std::shared_ptr<base_distribution>
as a class member, or a container value. At this point, to wrap this up, define whatever virtual methods you need in your base_distribution class, and implement them in the template subclasses appropriately.

To my knowledge, there is no "base distribution class" or generic distribution class, in C++. You do have a RandomNumberDistribution concept, but that's obviously not the same thing.
If you want a quick-and-dirty distribution class (and I do mean dirty), I currently use something like that (.h, .cpp).
As for your second question - you might need to have your templated class inherit from a single non-templated class which you can place in your vector (you'll need to use pointer members though, to avoid data slicing).

Related

Add different instantiations of a template class in the same container and call a template class method

Suppose I have these classes:
class A
{
// virtual methods
};
template<typename T>
class B : public A
{
void ANewMethodSpecificOfClassB(...){...};
}
I would like to add a subset of B classes into a container and from there, call ANewMethodSpecificOfClassB.
For example, given:
B<instanciation1> south_park;
B<instanciatoin2> family_guy;
suppose I want to put B<instanciation1> and B<instanciation2> in the same container (for example a vector): I cannot declare a std::vector<B> because B is not a real class, only B<instanciation1> and B<instanciation2> are.
Then I thought to define a vector using a (shared) pointer to the base class. However, doing so gives error when calling ANewMethodSpecificOfClassB because the method is not defined in the base class (and no, I can't modify the base class adding the method there).
Is there a way create a container with two different instances of a template classes and call a method that all of the instantiated classes have but not the parent class of the template class?
There are (at least) two ways around this:
You might define an intermediate class, AWithSpecificMethod:
class AWithSpecificMethod {
protected:
virtual ANewMethodSpecificOfClassB() const = 0;
};
Then have B<> descend either from A or from AWithSpecificMethod. You can do that using std::conditional<>, std::is_same<> et. al.
However, this way of solving it, at some point, creates several interfaces and immediate classes which are not true abstractions, just a notation of existence of method. Also, it's virtual => likely very slow.
You might store them in an std::variant<B<T1>, B<T2>, ...> and reconsider even if A is necessary as an interface class. This works if you know the possible types T1, T2, ... that you intend to work with (practically almost always). You can visit a variant using std::visit, which you usually pass a lambda and the variant:
std::variant<B<int>, B<char>> var;
std::visit([&](auto const& actual) {
// here actual is the concrete type
// either B<int> const& or B<char>&
}, var);

Does this example warrant the use of public inheritance

I'm trying to implement a library where Class1 provides about five public methods Method1 to Method5. Class2 provides two methods - Methods6 and Method7. And Class3 provides one method - Method8. Now, for the end user, I want to expose methods from combination of these classes. E.g. If the end user instantiates a class called Class1Class2, they should have access to Method1 to Method7, if they instantiate a class called Class1Class3, they should have access to Method1 to Method5 and Method8.
There are 3 different approaches I could think of (please suggest any others as well):
Multiple inheritance: Keep each of Class1, Class2 and Class3 as it is. Then, create a new class Class1Class2 that publicly multiple inherits from Class1 and Class2. Similarly I can create a class Class1Class3 that publicly multiple inherits from Class1 and Class3.
Multi-level inheritance: I could derive Class2 from Class1, and call that Class1Class2. And Class3 from Class1 and call that Class1Class3. And if we need Class1Class2Class3, we inherit that class from Class2 and Class3, which have both derived from Class1. Here, we would use virtual inheritance to resolve the diamond problem. I don't expect to use Class2Class3, so that shouldn't be a problem here.
Composition: Keep each of Class1, Class2 and Class3 as it is. Create Class1Class2 that implements each of the methods Method1 to Method7 and internally delegate them to the objects of Class1 and Class2 accordingly. Similarly, a Class1Class3 would compose objects of Class1 and Class3. With this approach we need to provide implementations for all the methods and delegate them to the composed objects.
While "Composition over inheritance" guideline is generally great for loose coupling of classes, etc., in the above case, where we have to do code reuse from separate concrete implementations, Approach 1 or 2 seem like better options.
You are only talking about code reuse here. I would think that's because you don't actually need nor want actual polymorphism. If this is indeed the case, then consider private inheritance and using to expose the parent methods.
For example:
class Class1Class2 : Class1, Class2 {
public:
using Class1::Method1;
// ...
using Class2::Method6;
// ...
};
Private inheritance, while technically being called inheritance, is very different from public inheritance, which itself is conceptually different from subtyping.
In C++ (and a lot of other languages that support OOP), public inheritance usually provides both subtyping and code reuse. However, it is entirely possible to derive a class with incorrect behavior in places that expect the parent class. This potentially undermines subtyping. It is also entirely possible to derive a class that does not reuse any of the implementation of the parent class. This potentially undermines code reuse.
Conceptually, subtyping is expressed by interface inheritance, while implementation inheritance is only one way to reuse code. The "composition over inheritance" saying, as far as I understand it, is about using other tools to reuse code because implementation inheritance often leads to bad code. However, there isn't really another way to achieve true subtyping than inheritance, so it may still be useful there1.
On the other hand, private inheritance is just an odd form of composition. It simply replaces the member with a private base class. An advantage of this is the ability to use using to easily expose the parts of that "member" you want to expose.
1 I personally don't like either forms of (public) inheritance, prefering static polymorphism and compile-time duck typing. However, I can happily work with interface inheritance, whereas I usually stay far away from implementation inheritance.
As you want easy combination, you might use template as variant of your first proposal:
template <typename ... Bases>
struct Derived : Bases...
{
};
using Class1Class2 = Derived<Class1, Class2>;
using Class1Class2Class3 = Derived<Class1, Class2, Class3>;
To make things more interesting you may employ CRTP. Here is an example:
template<typename Base>
class ClassA {
public:
void MethodA1() {static_cast<Base*>(this)->MethodA1_Impl();}
void MethodA2() {static_cast<Base*>(this)->MethodA2_Impl();}
};
template<typename Base>
class ClassB {
public:
void MethodB1() {static_cast<Base*>(this)->MethodB1_Impl();}
void MethodB2() {static_cast<Base*>(this)->MethodB2_Impl();}
};
template<typename Base>
class ClassC {
public:
void MethodC1() {static_cast<Base*>(this)->MethodC1_Impl();}
void MethodC2() {static_cast<Base*>(this)->MethodC2_Impl();}
};
class ClassABC: public ClassA<ClassABC>, public ClassB<ClassABC>, public ClassC<ClassABC> {
public:
//void MethodA1_Impl();
//void MethodA2_Impl();
//void MethodB1_Impl();
//void MethodB2_Impl();
//void MethodC1_Impl();
//void MethodC2_Impl();
};
You may uncomment and implement ANY subset of MethodXY_Impl(), and that would compile. The client code may call any method from MethodXY(). If there is no corresponding implementation - the compiler would produce an error.

Template based design opinion

I have this particular case and would need some opinion on some of the design aspects.
Basically, I have already defined classes ( which represents position in different spaces ) and the classes does not have a concrete relationship to each other.
So, I designed a template based interpolator which can work on the currently available position representing classes.
Roughly like,
template<typename TPoint>
class Interpolator
{
.....
some function
{
TPoint::CalculateCriticalAxis(point);
}
}
As you can see, there are some static functions defined in all position classes that can be accessed inside the interpolator.
So, now since somebodyelse who need to use the interpolator and define a new position(point) class, will have to know that he needs to define them by looking at the code since there is no base class for positions.
The question is how can I design a base class which will also contain static methods which user have to override. As I understand static methods can not be overridden. So, what is the easiest way to force implementing them if somebody want to define a new position(point) class.
I do not want to redesign it since there are legacy position classes that are not from me and they non related in some sense.
Thanks!
Use a static member function, defined as deleted. A [[deprecated( "message" )]] attribute allows you to print an error message when someone tries to access a missing implementation.
// May be, but doesn't need to be a template.
struct base_interface {
// Likewise, this could be templated.
[[deprecated( "Derived class must override calculation." )]]
static value_type calculate_something() = delete;
// "Public" interface, in the vein of the non-virtual idiom (NVI).
// This must be a template, and it can't be a member - it's a friend.
template< typename derived >
friend value_type something_of( derived const & o )
{ return o.calculate_something(); }
};
The well-known weakness of "duck typing" is that the user might not try to access the missing implementation. This is a different problem. Any solution amounts to accessing all the aspects of a proper derived class.
A base class can do this, but only carefully, because there are some issues:
The derived class will be incomplete within the definition of its base class. But, it will be complete within the definitions of member functions of the base class.
The existence of a complete derived class implementation should be verified, but you don't actually want to instantiate all parts of a derived class template, much less link it into the binary. "Too much" usage will bloat compile times and executable size, respectively.
One solution is to use static_assert and decltype inside a CRTP base class constructor.
// CRTP template, derived class must pass itself to base.
template< class derived >
class base_interface {
base_interface() {
static_assert ( std::is_same< decltype( derived::calculate_something() ),
typename derived::value_type >::value,
"derived class is missing calculate_something" );
}
// Just enough to allow the static_assert condition to evaluate as false.
static struct invalid calculate_something();
typedef void value_type;
};
http://coliru.stacked-crooked.com/a/b2c5f9bf8ed58a09
Note that this is a completely different solution from the first one. This prevents the CRTP base from being trivially default constructible, but that's a fairly small price to pay. Alternately, you could put the static_asserts in a different function that is sure to be accessed, and retain the trivial default constructor.

Choosing a design pattern for a class that might change its internal attributes

I have a class that holds arbitrary state and it's defined like this:
class AbstractFoo
{
};
template <class StatePolicy>
class Foo : public StatePolicy, public AbstractFoo
{
};
The state policy contains only protected attributes that represent the state.
The state might be the same for multiple behaviors and they can be replaced at runtime.
All Foo objects have the same interface to abstract the state itself and to enable storing Foo objects in containers.
I would like to find the least verbose and the most maintainable way to express this.
EDIT:
Here's some more info on my problem:
Foo is a class that represents a state and behavior of a certain hardware that can be changed either physically or through a UI (and there are multiple UIs).
I have four more questions:
1) Would a signal/slot mechanism will do?
2) Is it possible to bind every emitted signal from a slot in Foo to have a pointer to Foo like it's a member class?
3) Should I use a visitor instead and treat Foo as a visited class?
4) Why is the StatePolicy a bad design?
Here's the updated API:
class AbstractFoo
{
public:
virtual void /*or boost::signal*/ notify() = 0; // Updates the UI.
virtual void /*or boost::signal*/ updateState() = 0 // Updates the state
};
I don't understand your situation exactly, but here's my shot at it: what if you make an AbstractStatePolicy instead? Example:
class AbstractStatePolicy
{
};
class Foo
{
AbstractStatePolicy *state_policy;
public:
Foo(AbstractStatePolicy *state_policy)
: state_policy(state_policy)
{
}
};
This way, instead of statically defining Foo as a template using a StatePolicy, you can dynamically set the StatePolicy using an approach like this.
If you don't like the idea of having to specify the state_policy every time you create a Foo, consider using a default value or writing a factory to instantiate Foos.
I don't think what you have is a very sensible approach. You should have a pure virtual base class that describes what your implementations can actually do, and then you can create concrete classes that inherit from the base class using whatever state you would need. You would then be able to interact with the state through whatever interface you defined for that base class. Now, if you have arbitrary, dynamic attributes that can change at runtime, then a good way to accomplish that is with a map or dictionary type; you can either map from strings (names of attributes) to strings (representing the attribute values), or if you want a little bit more type safety, you map from strings (names of attributes), to instances of boost::any.

Using "super" in C++

My style of coding includes the following idiom:
class Derived : public Base
{
public :
typedef Base super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
This enables me to use "super" as an alias to Base, for example, in constructors:
Derived(int i, int j)
: super(i), J(j)
{
}
Or even when calling the method from the base class inside its overridden version:
void Derived::foo()
{
super::foo() ;
// ... And then, do something else
}
It can even be chained (I have still to find the use for that, though):
class DerivedDerived : public Derived
{
public :
typedef Derived super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
void DerivedDerived::bar()
{
super::bar() ; // will call Derived::bar
super::super::bar ; // will call Base::bar
// ... And then, do something else
}
Anyway, I find the use of "typedef super" very useful, for example, when Base is either verbose and/or templated.
The fact is that super is implemented in Java, as well as in C# (where it is called "base", unless I'm wrong). But C++ lacks this keyword.
So, my questions:
is this use of typedef super common/rare/never seen in the code you work with?
is this use of typedef super Ok (i.e. do you see strong or not so strong reasons to not use it)?
should "super" be a good thing, should it be somewhat standardized in C++, or is this use through a typedef enough already?
Edit: Roddy mentionned the fact the typedef should be private. This would mean any derived class would not be able to use it without redeclaring it. But I guess it would also prevent the super::super chaining (but who's gonna cry for that?).
Edit 2: Now, some months after massively using "super", I wholeheartedly agree with Roddy's viewpoint: "super" should be private.
Bjarne Stroustrup mentions in Design and Evolution of C++ that super as a keyword was considered by the ISO C++ Standards committee the first time C++ was standardized.
Dag Bruck proposed this extension, calling the base class "inherited." The proposal mentioned the multiple inheritance issue, and would have flagged ambiguous uses. Even Stroustrup was convinced.
After discussion, Dag Bruck (yes, the same person making the proposal) wrote that the proposal was implementable, technically sound, and free of major flaws, and handled multiple inheritance. On the other hand, there wasn't enough bang for the buck, and the committee should handle a thornier problem.
Michael Tiemann arrived late, and then showed that a typedef'ed super would work just fine, using the same technique that was asked about in this post.
So, no, this will probably never get standardized.
If you don't have a copy, Design and Evolution is well worth the cover price. Used copies can be had for about $10.
I've always used "inherited" rather than super. (Probably due to a Delphi background), and I always make it private, to avoid the problem when the 'inherited' is erroneously omitted from a class but a subclass tries to use it.
class MyClass : public MyBase
{
private: // Prevents erroneous use by other classes.
typedef MyBase inherited;
...
My standard 'code template' for creating new classes includes the typedef, so I have little opportunity to accidentally omit it.
I don't think the chained "super::super" suggestion is a good idea- If you're doing that, you're probably tied in very hard to a particular hierarchy, and changing it will likely break stuff badly.
One problem with this is that if you forget to (re-)define super for derived classes, then any call to super::something will compile fine but will probably not call the desired function.
For example:
class Base
{
public: virtual void foo() { ... }
};
class Derived: public Base
{
public:
typedef Base super;
virtual void foo()
{
super::foo(); // call superclass implementation
// do other stuff
...
}
};
class DerivedAgain: public Derived
{
public:
virtual void foo()
{
// Call superclass function
super::foo(); // oops, calls Base::foo() rather than Derived::foo()
...
}
};
(As pointed out by Martin York in the comments to this answer, this problem can be eliminated by making the typedef private rather than public or protected.)
FWIW Microsoft has added an extension for __super in their compiler.
I don't recall seeing this before, but at first glance I like it. As Ferruccio notes, it doesn't work well in the face of MI, but MI is more the exception than the rule and there's nothing that says something needs to be usable everywhere to be useful.
Super (or inherited) is Very Good Thing because if you need to stick another inheritance layer in between Base and Derived, you only have to change two things: 1. the "class Base: foo" and 2. the typedef
If I recall correctly, the C++ Standards committee was considering adding a keyword for this... until Michael Tiemann pointed out that this typedef trick works.
As for multiple inheritance, since it's under programmer control you can do whatever you want: maybe super1 and super2, or whatever.
I just found an alternate workaround. I have a big problem with the typedef approach which bit me today:
The typedef requires an exact copy of the class name. If someone changes the class name but doesn't change the typedef then you will run into problems.
So I came up with a better solution using a very simple template.
template <class C>
struct MakeAlias : C
{
typedef C BaseAlias;
};
So now, instead of
class Derived : public Base
{
private:
typedef Base Super;
};
you have
class Derived : public MakeAlias<Base>
{
// Can refer to Base as BaseAlias here
};
In this case, BaseAlias is not private and I've tried to guard against careless usage by selecting an type name that should alert other developers.
I've seen this idiom employed in many code bases and I'm pretty sure I've even seen it somewhere in Boost's libraries. However, as far as I remember the most common name is base (or Base) instead of super.
This idiom is especially useful if working with class templates. As an example, consider the following class (from a real project):
template <typename TText, typename TSpec>
class Finder<Index<TText, PizzaChili<TSpec>>, MyFinderType>
: public Finder<Index<TText, MyFinderImpl<TSpec>>, Default>
{
using TBase = Finder<Index<TText, MyFinderImpl<TSpec>>, Default>;
// …
}
The inheritance chain uses type arguments to achieve compile-time polymorphism. Unfortunately, the nesting level of these templates gets quite high. Therefore, meaningful abbreviations for the full type names are crucial for readability and maintainability.
I've quite often seen it used, sometimes as super_t, when the base is a complex template type (boost::iterator_adaptor does this, for example)
is this use of typedef super common/rare/never seen in the code you work with?
I have never seen this particular pattern in the C++ code I work with, but that doesn't mean it's not out there.
is this use of typedef super Ok (i.e. do you see strong or not so strong reasons to not use it)?
It doesn't allow for multiple inheritance (cleanly, anyway).
should "super" be a good thing, should it be somewhat standardized in C++, or is this use through a typedef enough already?
For the above cited reason (multiple inheritance), no. The reason why you see "super" in the other languages you listed is that they only support single inheritance, so there is no confusion as to what "super" is referring to. Granted, in those languages it IS useful but it doesn't really have a place in the C++ data model.
Oh, and FYI: C++/CLI supports this concept in the form of the "__super" keyword. Please note, though, that C++/CLI doesn't support multiple inheritance either.
One additional reason to use a typedef for the superclass is when you are using complex templates in the object's inheritance.
For instance:
template <typename T, size_t C, typename U>
class A
{ ... };
template <typename T>
class B : public A<T,99,T>
{ ... };
In class B it would be ideal to have a typedef for A otherwise you would be stuck repeating it everywhere you wanted to reference A's members.
In these cases it can work with multiple inheritance too, but you wouldn't have a typedef named 'super', it would be called 'base_A_t' or something like that.
--jeffk++
After migrating from Turbo Pascal to C++ back in the day, I used to do this in order to have an equivalent for the Turbo Pascal "inherited" keyword, which works the same way. However, after programming in C++ for a few years I stopped doing it. I found I just didn't need it very much.
I was trying to solve this exact same problem; I threw around a few ideas, such as using variadic templates and pack expansion to allow for an arbitrary number of parents, but I realized that would result in an implementation like 'super0' and 'super1'. I trashed it because that would be barely more useful than not having it to begin with.
My Solution involves a helper class PrimaryParent and is implemented as so:
template<typename BaseClass>
class PrimaryParent : virtual public BaseClass
{
protected:
using super = BaseClass;
public:
template<typename ...ArgTypes>
PrimaryParent<BaseClass>(ArgTypes... args) : BaseClass(args...){}
}
Then which ever class you want to use would be declared as such:
class MyObject : public PrimaryParent<SomeBaseClass>
{
public:
MyObject() : PrimaryParent<SomeBaseClass>(SomeParams) {}
}
To avoid the need to use virtual inheritance in PrimaryParenton BaseClass, a constructor taking a variable number of arguments is used to allow construction of BaseClass.
The reason behind the public inheritance of BaseClass into PrimaryParent is to let MyObject have full control over over the inheritance of BaseClass despite having a helper class between them.
This does mean that every class you want to have super must use the PrimaryParent helper class, and each child may only inherit from one class using PrimaryParent (hence the name).
Another restriction for this method, is MyObject can inherit only one class which inherits from PrimaryParent, and that one must be inherited using PrimaryParent. Here is what I mean:
class SomeOtherBase : public PrimaryParent<Ancestor>{}
class MixinClass {}
//Good
class BaseClass : public PrimaryParent<SomeOtherBase>, public MixinClass
{}
//Not Good (now 'super' is ambiguous)
class MyObject : public PrimaryParent<BaseClass>, public SomeOtherBase{}
//Also Not Good ('super' is again ambiguous)
class MyObject : public PrimaryParent<BaseClass>, public PrimaryParent<SomeOtherBase>{}
Before you discard this as an option because of the seeming number of restrictions and the fact there is a middle-man class between every inheritance, these things are not bad.
Multiple inheritance is a strong tool, but in most circumstances, there will be only one primary parent, and if there are other parents, they likely will be Mixin classes, or classes which don't inherit from PrimaryParent anyways. If multiple inheritance is still necessary (though many situations would benefit to use composition to define an object instead of inheritance), than just explicitly define super in that class and don't inherit from PrimaryParent.
The idea of having to define super in every class is not very appealing to me, using PrimaryParent allows for super, clearly an inheritence based alias, to stay in the class definition line instead of the class body where the data should go.
That might just be me though.
Of course every situation is different, but consider these things i have said when deciding which option to use.
I don't know whether it's rare or not, but I've certainly done the same thing.
As has been pointed out, the difficulty with making this part of the language itself is when a class makes use of multiple inheritance.
I use this from time to time. Just when I find myself typing out the base class type a couple of times, I'll replace it with a typedef similar to yours.
I think it can be a good use. As you say, if your base class is a template it can save typing. Also, template classes may take arguments that act as policies for how the template should work. You're free to change the base type without having to fix up all your references to it as long as the interface of the base remains compatible.
I think the use through the typedef is enough already. I can't see how it would be built into the language anyway because multiple inheritence means there can be many base classes, so you can typedef it as you see fit for the class you logically feel is the most important base class.
I use the __super keyword. But it's Microsoft specific:
http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx
I won't say much except present code with comments that demonstrates that super doesn't mean calling base!
super != base.
In short, what is "super" supposed to mean anyway? and then what is "base" supposed to mean?
super means, calling the last implementor of a method (not base method)
base means, choosing which class is default base in multiple inheritance.
This 2 rules apply to in class typedefs.
Consider library implementor and library user, who is super and who is base?
for more info here is working code for copy paste into your IDE:
#include <iostream>
// Library defiens 4 classes in typical library class hierarchy
class Abstract
{
public:
virtual void f() = 0;
};
class LibraryBase1 :
virtual public Abstract
{
public:
void f() override
{
std::cout << "Base1" << std::endl;
}
};
class LibraryBase2 :
virtual public Abstract
{
public:
void f() override
{
std::cout << "Base2" << std::endl;
}
};
class LibraryDerivate :
public LibraryBase1,
public LibraryBase2
{
// base is meaningfull only for this class,
// this class decides who is my base in multiple inheritance
private:
using base = LibraryBase1;
protected:
// this is super! base is not super but base!
using super = LibraryDerivate;
public:
void f() override
{
std::cout << "I'm super not my Base" << std::endl;
std::cout << "Calling my *default* base: " << std::endl;
base::f();
}
};
// Library user
struct UserBase :
public LibraryDerivate
{
protected:
// NOTE: If user overrides f() he must update who is super, in one class before base!
using super = UserBase; // this typedef is needed only so that most derived version
// is called, which calls next super in hierarchy.
// it's not needed here, just saying how to chain "super" calls if needed
// NOTE: User can't call base, base is a concept private to each class, super is not.
private:
using base = LibraryDerivate; // example of typedefing base.
};
struct UserDerived :
public UserBase
{
// NOTE: to typedef who is super here we would need to specify full name
// when calling super method, but in this sample is it's not needed.
// Good super is called, example of good super is last implementor of f()
// example of bad super is calling base (but which base??)
void f() override
{
super::f();
}
};
int main()
{
UserDerived derived;
// derived calls super implementation because that's what
// "super" is supposed to mean! super != base
derived.f();
// Yes it work with polymorphism!
Abstract* pUser = new LibraryDerivate;
pUser->f();
Abstract* pUserBase = new UserBase;
pUserBase->f();
}
Another important point here is this:
polymorphic call: calls downward
super call: calls upwards
inside main() we use polymorphic call downards that super calls upwards, not really useful in real life, but it demonstrates the difference.
The simple answer why c++ doesn't support "super" keyword is.
DDD(Deadly Diamond of Death) problem.
in multiple inheritance. Compiler will confuse which is superclass.
So which superclass is "D"'s superclass?? "Both" cannot be solution because "super" keyword is pointer.
This is a method I use which uses macros instead of a typedef. I know that this is not the C++ way of doing things but it can be convenient when chaining iterators together through inheritance when only the base class furthest down the hierarchy is acting upon an inherited offset.
For example:
// some header.h
#define CLASS some_iterator
#define SUPER_CLASS some_const_iterator
#define SUPER static_cast<SUPER_CLASS&>(*this)
template<typename T>
class CLASS : SUPER_CLASS {
typedef CLASS<T> class_type;
class_type& operator++();
};
template<typename T>
typename CLASS<T>::class_type CLASS<T>::operator++(
int)
{
class_type copy = *this;
// Macro
++SUPER;
// vs
// Typedef
// super::operator++();
return copy;
}
#undef CLASS
#undef SUPER_CLASS
#undef SUPER
The generic setup I use makes it very easy to read and copy/paste between the inheritance tree which have duplicate code but must be overridden because the return type has to match the current class.
One could use a lower-case super to replicate the behavior seen in Java but my coding style is to use all upper-case letters for macros.