I have a situation where I need to achieve polymorphism without vtable. Here is what I am trying to do
There is a class hierarchy: C extends B, B extends A
The idea is to declare a function pointer in A and constructors of B and C assign their corresponding methods to the function pointer in A
With the code below I am able to achieve polymorphism for class C but not for class B.
Obviously I am missing something here. I am not sure if this is even possible. Greatly appreciate any insights into this problem.
I can do this with the below code
A<C> *c = new C();
c->BasePrint(); //Reached C's Print
but not this
// A<B> *b = new B();
// b->BasePrint(); //Intentionally incorrect to demonstrate the problem.
Is there any way to achieve this?
template <typename T>
class A
{
public:
typedef void (T::*PrintFn)(void);
protected:
PrintFn printFn;
public:
void BasePrint()
{
if(printFn)
(((T*)this)->*printFn)();
}
};
template <typename T>
class B : public A<T>
{
public:
B()
{
printFn = &B::Print;
}
void Print()
{
//Print B
}
};
class C : public B<C>
{
public:
C()
{
printFn = &C::Print;
}
void Print()
{
//Print C
}
};
#include <iostream>
#include <typeinfo>
struct own_type {};
template<template<typename T>class CRTP, typename In, typename D>
struct DoCRTP: CRTP<In> {};
template<template<typename T>class CRTP, typename D>
struct DoCRTP<CRTP, own_type, D>: CRTP<D> {};
template<typename D>
struct A {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
A() {
std::cout << "A<" << typeid(D).name() << ">\n";
self()->print();
}
};
template<typename T=own_type>
struct B:DoCRTP<A, T, B<T>> {
B() {
std::cout << "B<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a B\n"; }
};
template<typename T=own_type>
struct C:DoCRTP<B, T, C<T>> {
C() {
std::cout << "C<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a C\n"; }
};
void test() {
std::cout << "Instance of B<>:\n";
B<> b;
std::cout << "Instance of C<>:\n";
C<> c;
}
int main() {
test();
}
Here we have a way you can pass in the most derived class, and if you pass in nothing you are assumed to be the most derived class.
However, there is a problem with your design -- A already fully knows its type situation, so there is no need for virtual behavior! BasePrint could static_cast<T*>(this)->Print() and you'd do away with your overhead.
The fundamental problem you have is that you are storing specific-type member function pointers in your base class A.
A template-less A could store pointers to non-specific type function pointers -- say "static" ones that explicitly take an A* as the first argument. In C++11, you could auto-build these functions from member functions. In C++03, std::bind should let you convert your member function pointers to D to functions that take an A* as the first argument.
You are not specifying the template parameter for B in:
A<B> *b = new B();
as opposed to its declaration:
template <typename T>
class B : public A<T>
You should go with something long the lines of:
A<B<X>> *b = new B<X>();
with X being a non templated type.
I can do this with the below code [...] but not this:
A<B> *b = new B();
b->BasePrint(); //Intentionally incorrect to demonstrate the problem.
Well, the problem here is that B is a class template, and you are not instantiating it. It doesn't have much to do with polymorphism nor with vtables. A class template is just a blueprint (well, a template in fact) for instantiating types by passing arguments to them, but it is not a type per se.
You should use some template arguments when instantiating B. For instance:
A<C>* b = new B<C>();
b->BasePrint();
And you should see this invoking B::Print(). Here is a live example.
Related
Is there a way that we can call derived class's method from base class object for which base doesn't provide an interface to call? I would like to do something like this
template<typename T>
struct A
{
using Derived = T;
void print()
{
static_cast<T*>(this)->print_();
}
void print_()
{
std::cout << "Base" << std::endl;
}
void a()
{
std::cout << "Aa" << std::endl;
}
};
struct B : public A<B>
{
void print_()
{
std::cout << "BD" << std::endl;
}
void b()
{
std::cout << "Bb" << std::endl;
}
};
struct C : public A<C>{
void c()
{
std::cout << "Cc" << std::endl;
}
};
int main()
{
A<B> b;
A<C> c;
b.print();
c.print();
B bd;
b.a();
bd.b(); // This works
// b.b(); // I understand this doesn't work, but I want to make this work.
C bc;
c.a();
bc.c(); // Same as class A<C> and C
}
I can provide interfaces to call those functions but I would like to know if this is achievable in the first place. Any solutions or comments on feasibility is much appreciated.
PS: I am just curious about this, as I got an unintentional error when I incorrectly instantiated the class.
Is there a way that we can call derived class's method from base class object for which base doesn't provide an interface to call?
Yes, as Jarod42 suggested, you can implement operator-> in A. You can't overload operator. so you'll have to use -> when calling such methods.
template<typename T>
struct A {
T* operator->() { return static_cast<T*>(this); }
};
You will now be able to compile this:
A<B> b;
b->print_();
b->b();
But: Your program will have undefined behavior. b is not a B. It's an A<B> that doesn't inherit from B so you will call non-static member functions on a non-existing object.
I suggest that you prevent instantiating A:s that doesn't have the proper CRTP relationship.
template<typename T>
struct A {
T* operator->() { return static_cast<T*>(this); }
private:
A() = default; // hidden from all ...
friend T; // ... except T
};
You can now instantiate B, but not A<B> or C if someone makes a bogus inheritance like this:
struct X {};
struct C : A<X> {}; // C can't be instantiated. A is friend of X, not C
Demo
Simple case: If you add a static function there is a safe way (because it would not access instance date).
Complicated case: the b.b(): This almost works but it's definitely a bad idea. As long as function does not refer to any instance variable it would be relatively safe. But otherwise it will definitely crash. The reason is b does not have B instance.
template<typename T>
struct A
{
typedef typename T Derived;
typedef typename A<T> AT;
void print()
{
static_cast<T*>(this)->print_();
}
void print_()
{
std::cout << "Base" << std::endl;
}
void a()
{
std::cout << "Aa" << std::endl;
}
//these conversion operators are for b.b() case. very bad idea!
operator Derived* () {
return static_cast<T*>(this);
}
operator Derived& () {
return static_cast<Derived&>(*this);
}
};
struct B : public A<B>
{
void print_()
{
std::cout << "BD" << std::endl;
}
static void static_b()
{
std::cout << "Bb::static_b" << std::endl;
}
void b()
{
std::cout << "Bb::b" << std::endl;
}
};
void test()
{
b.A<B>::Derived::static_b(); // This should work.
b.AT::Derived::static_b(); // This works with "AT" but it's recursive template. Not good.
((B&)b).b(); //This works but even though operator is implicit, it cannot implicitly know what to do. Nor will "auto".
//This works but even though operator is implicit, it cannot implicitly know what to do. Nor will "auto".
B& br = b;
br.b();
}
I have these two classes:
class A {
public:
A() { m_ptr = NULL; }
void (*m_ptr)();
void a() { if (m_ptr) m_ptr(); }
};
class B : public A {
public:
B() { m_ptr = b; }
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
And I want to use them like this:
B b;
b.a();
and get the following to be called B::b().
Of course this is not being compiled as B::b is not of type void(*)().
How can I make it work?
UPDATE. To whom who asks "why?" and "what for?".
The class A is a very basic class which has many successors in production code. The class B is 6-th successor and I want to extend A (the most convinient place) to call there one more method (from B) which can be present and may be not in another successors af A and B.
A virtual method with empty body can be employed for that but it is ugly and I want to avoid it. Abstract method even more so (because of existing derived successors code).
I don't want to use external function of type void (*)() to not loose access to internal data of all hierarchy.
You can't make it work as your classes are defined now.
Calling a non-static member function of another class requires an instance of that class. You either need to store a reference to the object that owns the member function when storing the function pointer, or pass a reference to the object when you make the call to A::a.
You also need to declare m_ptr with the type void (B::*)(), which is pointer to member of B that is a function taking no parameters and returning void.
Look at this example:
class A {
public:
A() { m_ptr = nullptr; }
void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
void (B::*m_ptr)(); // Pointer to member function of B.
};
class B : public A {
public:
B() { m_ptr = &B::b; } // Adress of qualified function.
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
Now we can call B::b like this:
B b;
b.a(b); // Pass reference to b when calling.
Your use of inheritence in this way is confusing as it implies that the real problem you are trying to solve is to invoka a member of a derived class through the base class. This is usually accomplished using a simple virtual function like this:
class A {
public:
virtual ~A() {}
void a() const { b(); } // Call b.
private:
virtual void b() const {}
};
class B : public A {
public:
virtual void b() const override { // C++11 override specifier (optional).
std::cout << "B::b() is called" << std::endl;
}
};
And used like this:
B b;
b.a(); // B::b is called.
Well, probably not the purpose of this exercise, but you can simply declare static void b() if you want to make it work.
Another option is to declare friend void b(), but then the "B::b() is called" printout would be stating a wrong fact.
I would suggest using CRTP since you want to avoid virtual mechanism. Note, however, your code might require some design changes to accommodate this pattern. But it does provide type safety and has no run-time overhead. Hope it helps.
Code on ideone.com:
#include <iostream>
#include <type_traits>
namespace so {
class B;
template<typename T>
class A {
public:
template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
void foo_A() {
std::cout << "foo_A : ";
static_cast<U *>(this)->foo_B();
}
};
class B: public A<B> {
public:
void foo_B() {
std::cout << "foo_B" << std::endl;
}
};
class C: public A<C> {
public:
void foo_C() {
std::cout << "foo_C" << std::endl;
}
};
} // namespace so
int main() {
so::B b_;
so::C c_;
b_.foo_A();
b_.foo_B();
//c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
c_.foo_C();
return (0);
}
Program output:
foo_A : foo_B
foo_B
foo_C
I am not sure how to ask this, but hopefully someone will understand. Lets say I have 3 different classes. Class A, Class B and Class C. Class C should take either Class A or Class B as a parameter in the constructor and store it in a private variable.
This is easy with overloaded constructors. My question is how can Class C automagically use the correct class depending on what constructor was used? (Note these 2 classes are similar, but come from different libraries and thus no shared base class). Is this possible with templates? I do not have a lot of experience with templates.
You can do it quite easy with templates:
class A;
class B;
template<class AorB>
class C
{
public:
C(AorB aorb)
: aorb_(aorb)
{ }
private:
AorB aorb_;
};
What this does is that inside the class C the identifier AorB can be used as any other class, in fact it doesn't even have to be an instance of A or B but can be any class.
Can be used like this:
A myA;
B myB;
C<A> myCWithA(myA);
C<B> myCWithB(myB);
There is however one thing you have to remember when creating classes using templates: The specification and implementation can no longer be split into separate header and source files. All of the code have to be available in the header file.
The syntax of the member functions are also a little different.
Example:
template<class T>
class C
{
public:
...
void someFunction();
};
template<class T>
C<T>::someFunction()
{
...
}
Yes, this is possible with templates:
#include <iostream>
template<class T>
class C {
public:
C(T const& ref) : ref(ref) {}
void doStuff() const {
ref.doStuff();
}
private:
T ref;
};
class A {
public:
void doStuff() const {
std::cout << "A::doStuff" << std::endl;
}
};
class B {
public:
void doStuff() const {
std::cout << "B::doStuff" << std::endl;
}
};
int main() {
C<A> foo((A()));
foo.doStuff();
C<B> bar((B()));
bar.doStuff();
}
I am trying to use template meta-programming to determine the base class. Is there a way to get the base class automatically without explicitly specializing for each derived class?
class foo { public: char * Name() { return "foo"; }; };
class bar : public foo { public: char * Name() { return "bar"; }; };
template< typename T > struct ClassInfo { typedef T Base; };
template<> struct ClassInfo<bar> { typedef foo Base; };
int main()
{
ClassInfo<foo>::Base A;
ClassInfo<bar>::Base B;
std::cout << A.Name(); //foo
std::cout << B.Name(); //foo
}
for right now any automatic method would need to select the first declared base and would fail for private bases.
It's possible with C++11 and decltype. For that, we'll exploit that a pointer-to-member is not a pointer into the derived class when the member is inherited from a base class.
For example:
struct base{
void f(){}
};
struct derived : base{};
The type of &derived::f will be void (base::*)(), not void (derived::*)(). This was already true in C++03, but it was impossible to get the base class type without actually specifying it. With decltype, it's easy and only needs this little function:
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class U>
T base_of(U T::*);
Usage:
#include <iostream>
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class R>
T base_of(R T::*);
struct base{
void f(){}
void name(){ std::cout << "base::name()\n"; }
};
struct derived : base{
void name(){ std::cout << "derived::name()\n"; }
};
struct not_deducible : base{
void f(){}
void name(){ std::cout << "not_deducible::name()\n"; }
};
int main(){
decltype(base_of(&derived::f)) a;
decltype(base_of(&base::f)) b;
decltype(base_of(¬_deducible::f)) c;
a.name();
b.name();
c.name();
}
Output:
base::name()
base::name()
not_deducible::name()
As the last example shows, you need to use a member that is actually an inherited member of the base class you're interested in.
There are more flaws, however: The member must also be unambiguously identify a base class member:
struct base2{ void f(){} };
struct not_deducible2 : base, base2{};
int main(){
decltype(base_of(¬_deducible2::f)) x; // error: 'f' is ambiguous
}
That's the best you can get though, without compiler support.
My solutions are not really automatic, but the best I can think of.
Intrusive C++03 solution:
class B {};
class A : public B
{
public:
typedef B Base;
};
Non-intrusive C++03 solution:
class B {};
class A : public B {};
template<class T>
struct TypeInfo;
template<>
struct TypeInfo<A>
{
typedef B Base;
};
I am not aware of any base-class-selecting template, and I'm not sure one exists or is even a good idea. There are many ways in which this breaks extensibility and goes against the spirit of inheritance. When bar publicly inherits foo, bar is a foo for all practical purposes, and client code shouldn't need to distinguish base class and derived class.
A public typedef in the base class often scratches the itches you might need to have scratched and is clearer:
class foo { public: typedef foo name_making_type; ... };
int main() {
Foo::name_making_type a;
Bar::name_making_type b;
}
What's with the base class? Are you a .NET or Java programmer?
C++ supports multiple inheritance, and also does not have a global common base class. So a C++ type may have zero, one, or many base classes. Use of the definite article is therefore contraindicated.
Since the base class makes no sense, there's no way to find it.
I am looking for a portable resolution for similar problems for months. But I don't find it yet.
G++ has __bases and __direct_bases. You can wrap them in a type list and then access any one of its elements, e.g. a std::tuple with std::tuple_element. See libstdc++'s <tr2/type_traits> for usage.
However, this is not portable. Clang++ currently has no such intrinsics.
With C++11, you can create a intrusive method to always have a base_t member, when your class only inherits from one parent:
template<class base_type>
struct labeled_base : public base_type
{
using base_t = base_type; // The original parent type
using base::base; // Inherit constructors
protected:
using base = labeled_base; // The real parent type
};
struct A { virtual void f() {} };
struct my_class : labeled_base<A>
{
my_class() : parent_t(required_params) {}
void f() override
{
// do_something_prefix();
base_t::f();
// do_something_postfix();
}
};
With that class, you will always have a parent_t alias, to call the parent constructors as if it were the base constructors with a (probably) shorter name, and a base_t alias, to make your class non-aware of the base class type name if it's long or heavily templated.
The parent_t alias is protected to don't expose it to the public. If you don't want the base_t alias is public, you can always inherit labeled_base as protected or private, no need of changing the labeled_base class definition.
That base should have 0 runtime or space overhead since its methods are inline, do nothing, and has no own attributes.
Recently when I reading Unreal Engine source code, I found a piece of code meet your requirement.
Simplified code is below:
#include <iostream>
#include <type_traits>
template<typename T>
struct TGetBaseTypeHelper
{
template<typename InternalType> static typename InternalType::DerivedType Test(const typename InternalType::DerivedType*);
template<typename InternalType> static void Test(...);
using Type = decltype(Test<T>(nullptr));
};
struct Base
{
using DerivedType = Base;
static void Print()
{
std::cout << "Base Logger" << std::endl;
}
};
struct Derived1 : Base
{
using BaseType = typename TGetBaseTypeHelper<Derived1>::Type;
using DerivedType = Derived1;
static void Print()
{
std::cout << "Derived1 Logger" << std::endl;
}
};
struct Derived2 : Derived1
{
using BaseType = typename TGetBaseTypeHelper<Derived2>::Type;
using DerivedType = Derived2;
static void Print()
{
std::cout << "Derived2 Logger" << std::endl;
}
};
int main()
{
Derived1::BaseType::Print();
Derived2::BaseType::Print();
}
Using a macro below to wrap those code make it simple:
#define DECLARE_BASE(T) \
public: \
using BaseType = typename TGetBaseTypeHelper<T>::Type; \
using DerivedType = T;
I got confused when first seeing these code. After I read #Xeo 's answer and #juanchopanza 's answer, I got the point.
Here's the keypoint why it works:
The decltype expression is part of the member declaration, which does
not have access to data members or member functions declared after
it.
For example:
In the declaration of class Derived1, when declaring Derived1::BaseType, Derived1::BaseType doesn't know the existence of Derived1::DerivedType. Because Derived1::BaseType is declared before Derived1::DerivedType. So the value of Derived1::BaseType is Base not Derived1.
If you have something like this:
#include <iostream>
template<typename T> class A
{
public:
void func()
{
T::func();
}
};
class B : public A<B>
{
public:
virtual void func()
{
std::cout << "into func";
}
};
class C : public B
{
};
int main()
{
C c;
c.func();
return 0;
}
Is func() dynamically dispatched?
How could you implement class A such that if B has a virtual override, that it is dynamically dispatched, but statically dispatched if B doesn't?
Edit: My code didn't compile? Sorry guys. I'm kinda ill right now. My new code also doesn't compile, but that's part of the question. Also, this question is for me, not the faq.
#include <iostream>
template<typename T> class A
{
public:
void func()
{
T::func();
}
};
class B : public A<B>
{
public:
virtual void func()
{
std::cout << "in B::func()\n";
}
};
class C : public B
{
public:
virtual void func() {
std::cout << "in C::func()\n";
}
};
class D : public A<D> {
void func() {
std::cout << "in D::func()\n";
}
};
class E : public D {
void func() {
std::cout << "in E::func()\n";
}
};
int main()
{
C c;
c.func();
A<B>& ref = c;
ref.func(); // Invokes dynamic lookup, as B declared itself virtual
A<D>* ptr = new E;
ptr->func(); // Calls D::func statically as D did not declare itself virtual
std::cin.get();
return 0;
}
visual studio 2010\projects\temp\temp\main.cpp(8): error C2352: 'B::func' : illegal call of non-static member function
visual studio 2010\projects\temp\temp\main.cpp(15) : see declaration of 'B::func'
visual studio 2010\projects\temp\temp\main.cpp(7) : while compiling class template member function 'void A<T>::func(void)'
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(13) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
I'm not sure I understand what you're asking, but it appears you are missing the essential CRTP cast:
template<class T>
struct A {
void func() {
T& self = *static_cast<T*>(this); // CRTP cast
self.func();
}
};
struct V : A<V> { // B for the case of virtual func
virtual void func() {
std::cout << "V::func\n";
}
};
struct NV : A<NV> { // B for the case of non-virtual func
void func() {
std::cout << "NV::func\n";
}
};
If T does not declare its own func, this will be infinite recursion as self.func will find A<T>::func. This is true even if a derived class of T (e.g. DV below) declares its own func but T does not.
Test with different final overrider to show dispatch works as advertised:
struct DV : V {
virtual void func() {
std::cout << "DV::func\n";
}
};
struct DNV : NV {
void func() {
std::cout << "DNV::func\n";
}
};
template<class B>
void call(A<B>& a) {
a.func(); // always calls A<T>::func
}
int main() {
DV dv;
call(dv); // uses virtual dispatch, finds DV::func
DNV dnv;
call(dnv); // no virtual dispatch, finds NV::func
return 0;
}
How could you implement class A such that if B has a virtual override, that it is dynamically dispatched, but statically dispatched if B doesn't?
Somewhat contradictory, isn't it? A user of class A may know nothing about B or C. If you have a reference to an A, the only way to know if func() needs dynamic dispatch is to consult the vtable. Since A::func() is not virtual there is no entry for it and thus nowhere to put the information. Once you make it virtual you're consulting the vtable and it's dynamic dispatch.
The only way to get direct function calls (or inlines) would be with non-virtual functions and no indirection through base class pointers.
Edit: I think the idiom for this in Scala would be class C: public B, public A<C> (repeating the trait with the child class) but this does not work in C++ because it makes the members of A<T> ambiguous in C.
In your particular example, there's no need for dynamic dispatch because the type of c is known at compile time. The call to B::func will be hard coded.
If you were calling func through a B*, then you would be calling a virtual function. But in your highly contrived example, that would get you to B::func once again.
It doesn't make much sense to talk about dynamic dispatch from an A* since A is a template class - you can't make a generic A, only one that is bound to a particular subclass.
How could you implement class A such that if B has a virtual override, that it is dynamically dispatched, but statically dispatched if B doesn't?
As others have noticed, it's really hard to make sense of that question, but it made me remember something I have learned a long time ago, so here's a very long shot at answering your question:
template<typename Base> class A : private Base
{
public:
void func()
{
std::count << "A::func";
}
};
Given this, it depends on A's base whether func() is virtual. If Base declares it virtual then it will be virtual in A, too. Otherwise it won't. See this:
class V
{
public:
virtual void func() {}
};
class NV
{
};
class B : public A<V> // makes func() virtual
{
public:
void func()
{
std::count << "B::func";
}
};
class C : public A<NV> // makes func() non-virtual
{
public:
void func()
{
std::count << "C::func";
}
};
Would this happen to answer your question?
Whether the function is dynamically dispatched or not depends on two things:
a) whether the object expression is a reference or pointer type
b) whether the function (to which overload resolution resolves to) is virtual or not.
Coming to your code now:
C c;
c.func(); // object expression is not of pointer/reference type.
// So static binding
A <B> & ref = c;
ref.func(); // object expression is of reference type, but func is
// not virtual. So static binding
A<D>* ptr = new D;
ptr->func(); // object expression is of pointer type, but func is not
// virtual. So static binding
So in short, 'func' is not dynamically dispatched.
Note that :: suppresses virtual function call mechanism.
$10.3/12- "Explicit qualification with
the scope operator (5.1) suppresses
the virtual "call mechanism.
The code in OP2 gives error because the syntax X::Y can be used to invoke 'Y' in the scope of 'X' only if 'Y' is a static member in the scope of 'X'.
Seems you just had to add a little trace and usage to answer your own question...
#include <iostream>
template<typename T> struct A {
void func() {
T::func();
}
};
struct B1 : A<B1> {
virtual void func() {
std::cout << "virtual void B1::func();\n";
}
};
struct B2 : A<B2> {
void func() {
std::cout << "void B2::func();\n";
}
};
struct C1 : B1 { };
struct C2 : B2 { };
struct C1a : B1 {
virtual void func() {
std::cout << "virtual void C1a::func();\n";
}
};
struct C2a : B2 {
virtual void func() {
std::cout << "virtual void C2a::func();\n";
}
};
int main()
{
C1 c1;
c1.func();
C2 c2;
c2.func();
B1* p_B1 = new C1a;
p_B1->func();
B2* p_B2 = new C2a;
p_B2->func();
}
Output:
virtual void B1::func();
void B2::func();
virtual void C1a::func();
void B2::func();
Conclusion: A does take on the virtual-ness of B's func.