I understand why you cannot simply cast a derived class member function pointer to base class member function pointer as explained here.
But, given this snippet:
struct base
{
virtual void foo() = 0;
};
struct derived : base
{
void foo() override {};
};
struct invoker
{
typedef void(base::*target)();
invoker(base* b, target t)
{
(b->*t)();
}
};
template<typename B, typename D>
void (B::*cast(void (D::*method)()))()
{
return static_cast<void(B::*)()>(method);
}
derived d;
invoker bad(&d, &derived::foo); //C2664
invoker good(&d, cast<base>(&derived::foo));
I wanted to ask is it possible to decorate the base function signature so that compiler understands it is a pure virtual method and and it will be implemented somewhere across the hierarchy (otherwise I could not construct an object of type B)? I understand why I can't do this with normal functions, but IMHO in case of a pure virtual function the compiler has a guarantee it will be implemented (in case it was not done I would get an error about the class B not about the cast).
There's no need to manipulate the type of &derived::foo. One can just use &base::foo instead.
Pointers to member functions respect virtuality. This call
base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();
will actually call derived::foo, exactly like a simple call pBase->foo() would.
Even if there's a guarantee that it's implemented, it might use additional data members declared only in derived. A possible solution is to use function pointers and pass this as the first parameter (this also shows you why you cannot do it via virtual).
Consider the following diamond hierarchy:
struct base {
virtual void foo() = 0;
};
struct D1 : public virtual base {
virtual void foo() override;
};
struct D2 : public virtual base {
virtual void foo() override;
};
struct Derived : public virtual D1, D2 {
virtual void foo() final;
};
Now consider a scenario where a upcast is allowed from Derived::* to base::* . Which function should be invoked? The compiler loses information about which of D1::foo, D2::foo or Derived::foo you wish to call since that information has been cast away. To avoid this sort of ambiguity such an upcast is disallowed.
Related
Is there any point to making virtual member functions, overridden from a base class private, if those are public in the base class?
struct base {
virtual void a();
};
struct derived : base {
// ...
private:
void a() override;
};
If you are forced to do a 2-phase construction on the implementation class (i.e. have an init() method as well as or instead of a constructor that has to be called (I know, but there are reasons), then this stops you calling any /other/ methods directly on the instance pointer before you pass it back as an interface pointer. Go the extra mile, make the inheritance private, and have your one public init function return the interface pointer!
Another reason is you just don't /need/ to write public: in a final implementation class declaration, so then by default everything is private. But why you would do that and use struct instead of class I don't know. Perhaps this was converted from class at some point due to a style war?
Looking at your design, I see one cannot call derived::a directly, but only through a base interface.
Is there any point? Consider that, once we have a derived instance, we can always up-cast to its base, so given
derived d;
while d.a() wouldn't compile, we can always do
base & b = d;
b.a(); //which actually calls derived::a
In other words: derived::a is not that private, after all, and I would discourage this design, which can be confusing to the user.
Things change if the members private in derived are private in base, as well: this time it is clear that they just cannot be called directly, outside base or derived.
Let's say we have a couple of functions, and want them to be called conditionally, according to a value passed as an argument to a third one:
struct base
{
void dosomething(bool x)
{
if(x)
{
do_this();
}
else
{
do_that();
}
}
private:
virtual void do_this(){}
virtual void do_that(){}
};
Thus a derived class could be like:
struct derived : base
{
private:
void do_this() override { }
void do_that() override { }
};
and no other class can call them, unless it extended base itself:
derived d;
d.dosomething(true); //will call do_this() in derived
d.dosomething(false); //will call do_that() in derived
d.do_that() //won't compile
Yes, if you inherit the base class as private. Otherwise, it is more of a weird explicit-like restriction - user has to has to make an explicit conversion to use the function - it is generally ill advised as few will be able to comprehend the author's intention.
If you want to restrict some functions from base class, make a private/protected inheritance and via using keyword declare which base-methods you want to be protected/public in the derived class.
The same reasoning as for non-virtual methods applies: If only the class itself is supposed to call it make it private.
Consider the template method pattern:
struct base {
void foo() { a() ; b(); }
virtual void a() = 0;
virtual void b() = 0;
};
struct derived : base {
private:
void a() override {}
void b() override {}
};
int main()
{
derived().foo();
}
Perhaps a and b should have been protected, but anyhow the derived can change accesibility and it requires some documentation so that derived knows how it is supposed to implement a and b.
EDIT: Ok as I see now this changes the case a lot so the more precise scenario is as such:
The hierarchy I currently have is somewhat similar to this:
class IBase() { virtual void Foo() = 0; };
class Base() : public IBase { virtual void Foo() { } };
class IDerived() { virtual void Bar() = 0; };
template<typename TT, typename TB, typename... TI>
class Derived : public Base, public IDerived { virtual void Bar() {}};
template<typename TT, typename TB, typename... TI>
IBase* CreateDerived() { return new Derived(); }
IBase* derived = CreateDerived<some types...>();
I am getting error with Visual Studio while trying to cast an object and call a function:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
All calls of IBase interface through derived work fine but when I try to cast derived to IDerived I get the error calling any function:
IDerived* d = (IDerived*)derived;
d->Bar(); <- boom error ;)
I guess that such cast is illegal but how can I cast the pointer so that I can get access to IDerived interface methods (preferably without dynamic_cast I would prefer a good and portable hack if one exists ;))? Is it possible somehow to calculate offset to the pointer so that the proper vtable is used and everything works as it should ?
I am programming for quite a long time but I always dodged all those fancy-shmancy over engineered systems with tons of interfaces and templates and now I am doomed to make one myself.
EDIT: Now as you can see this gets tricky and difficult. I don't know the exact type of the Derived I am getting as it is templated, also the function CreateDerived is templated and returns interface.
Also, one of the requirements is not to use dynamic_cast (RTTI is disabled in the project)
You are performing a cross-cast; IBase and IDerived are unrelated. You need to cast to Derived first and then to IDerived. If you used a static_cast rather than a C cast the compiler would have caught this for you at compile-time.
I assume you know that the IBase is really a Derived because you used a C cast, but if you don't then you can also use dynamic_cast to perform cross-casts safely.
EDIT: If you can't use RTTI and you don't know the dynamic type of the object then virtual inheritance and dynamic_cast go out of the window. When you call CreateDerived it looks like you do know the dynamic type of the object (because of its template arguments) so you could have a std::map<IBase*, IDerived*> and then after the CreateDerived<TT, TB, TI...>() call you can static_cast the IBase* to Derived<TT, TB, TI...>* and then insert the pointer as both the key and value into the map.
Just enable RTTI; this is getting complicated. >.<
EDIT 2: Alternatively, you seem to know that the object pointed at by the IBase* does also derive from IDerived*. If you can modify the class hierarchy you can have an abstract base class that derives from both IBase and IDerived and then have Derived derive from this new base class. Then you can static_cast from an IBase* to the new class in the hierarchy and then to IDerived*.
It would look something like this:
class IBase { virtual void Foo() = 0; };
class Base : public IBase { virtual void Foo() { } };
class IDerived { virtual void Bar() = 0; };
class BaseAndDerived : public Base, public IDerived { };
template<typename TT, typename TB, typename... TI>
class Derived : public BaseAndDerived { virtual void Bar() {}};
Say I have a base class and a derived class.
class Base {
public:
void A(int x, int y) {do something}
void B() {
A(x,y);
do something;
}
};
class Derived : public Base {
void A() {do something else};
};
Derived derived1;
derived1.B();
The signatures of the functions are different, will the B call the derived A or the base A? Iif it will call the derived B, I guess it will dismiss the parameters?
what if the derived A needed different parameters rather than no parameters, would I have to copy B's entire code into the derived class just to change the way B calls A?
A function's code is always evaluated in the context of the class in which it is defined. This includes determining which function each expression calls. So inside Base::B(), the call A(x, y) is translated by the compiler as a call to Base::A. Even if you later call derived1.B(), it will call derived1 . Base::A (pseudo-syntax).
The only thing which changes this slightly is virtual functions. However, even with them, the rules are similar. Overload resolution (which is basically the process of matching a function name & signature to a call expression) is done in the context of the class where the containing function is defined. If the resolution leads to a virtual function being selected, the virtual call mechanism will then be invoked at runtime to call the appropriate override of that function.
Let's consider this example:
struct Base {
virtual void foo(int);
virtual void bar() { foo(0.0); }
};
struct Derived : Base {
virtual void foo(int);
virtual void foo(double);
};
Derived d;
d.bar();
Even in this example, calling d.bar() will call Derived::foo(int). That's because the call-to-signature matching was done in the context of Base, which only sees foo(int) and employs the implicit conversion from double to int.
Two reasons force Base::B to call Base::A not Derived::A
It's calling A with specific overload: A(int, int)
Base::A and Base::B are not virtual, so it calls Base::A. The code is not polymorphic.
The simplest example to show a how a virtual method works is:
class Base {
public:
virtual void A() {
// do job #1
}
};
class Derived : public Base {
public:
virtual void A() {
// do job #2
}
};
// ...
Derived derived1;
Base *base = &derived1;
base->A(); // <---- It calls `Derived::A()` and does job #2
But, if you write A in B with different parameter (overload it), you have to call it explicitly with actual arguments.
Say I have the following code:
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->foo_impl(); //A
(*static_cast<Derived*>(this)).foo_impl(); //B
}
};
class Derived : public Base<Derived> {
private:
void foo_impl() {
bar();
}
};
A few questions:
Will line A generate a virtual function call? Although the majority of what I can find on the internet recommends doing things this way, to me I don't see how the compiler can do static dispatch considering that a pointer to Derived could still actually point to an object of type Derived2 where Derived2 : public Derived.
Does line B fix the issue I brought up in my previous point (if applicable)? It seems like it would, considering that now the call is not on a pointer any more and thus using *. would avoid a virtual function call. But if the compiler treats the dereferenced cast as a reference type, it could still generate a virtual function call... in that case, what is the workaround?
Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?
Will line A generate a virtual function call?
Yes. foo_impl() is virtual and Derived overrides it. Even though foo_impl() in Derived is not explicitly tagged as virtual, it is in the base class, and this is enough to make it a virtual function.
Does line B fix the issue I brought up in my previous point (if applicable)?
No. It does not matter if the call is on a pointer or on a reference: the compiler still won't know whether you are invoking the function foo_impl() on an instance of a class that derives from Derived, or on a direct instance of Derived. Thus, the call is performed through a vtable.
To see what I mean:
#include <iostream>
using namespace std;
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->foo_impl();
(*static_cast<Derived*>(this)).foo_impl();
}
};
class Derived : public Base<Derived> {
public:
void foo_impl() {
cout << "Derived::foo_impl()" << endl;
}
};
class MoreDerived : public Derived {
public:
void foo_impl() {
cout << "MoreDerived::foo_impl()" << endl;
}
};
int main()
{
MoreDerived d;
d.foo(); // Will output "MoreDerived::foo_impl()" twice
}
Finally:
Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?
In theory, yes. The final keyword would make it impossible to override that function in subclasses of Derived. Thus, when performing a function call to foo_impl() through a pointer to Derived, the compiler could resolve the call statically. However, to the best of my knowledge, compilers are not required to do so by the C++ Standard.
CONCLUSION:
In any case, I believe what you actually want to do is not to declare the foo_impl() function at all in the base class. This is normally the case when you use the CRTP. Additionally, you will have to declare class Base<Derived> a friend of Derived if you want it to access Derived's private function foo_impl(). Otherwise, you can make foo_impl() public.
The common idiom for the CRTP does not involve declaring the pure virtual functions in the base. As you mention in one of the comments, that means that the compiler will not enforce the definition of the member in the derived type (other than through use, if there is any use of foo in the base, that requires the presence of foo_impl in the derived type).
While I would stick to the common idiom and not define the pure virtual function in the base, but, if you really feel you need to do it, you can disable dynamic dispatch by adding extra qualification:
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->Derived::foo_impl();
// ^^^^^^^^^
}
};
The use of the extra qualification Derived:: disables dynamic dispatch, and that call will be statically resolved to Derived::foo_impl. Note that this comes will all of the usual caveats: you have a class with a virtual function and paying the cost of the virtual pointer per object, but you cannot override that virtual function in a most derived type, as the use in the CRTP base is blocking dynamic dispatch...
The extra verbiage in lines A and B have absolutely no effect on
the generated code. I don't know who recommends this (I've never seen
it), but in practice, the only time it might have an effect is
if the function isn't virtual. Just write foo_impl(), and be
done with it.
There is a means of avoiding the virtual function call if the
compiler knows the derived type. I've seen it used for
vector-like classes (where there are different implementations,
e.g. normal, sparse, etc. of the vector):
template <typename T>
class Base
{
private:
virtual T& getValue( int index ) = 0;
public:
T& operator[]( int index ) { return getValue( index ); }
};
template <typename T>
class Derived : public Base<T>
{
private:
virtual T& getValue( int index )
{
return operator[]( index );
}
public:
T& operator[]( index )
{
// find element and return it.
}
};
The idea here is that you normally only work through references
to the base class, but if performance becomes an issue, because
you're using [] in a tight loop, you can dynamic_cast to the
derived class before the loop, and use [] on the derived
class.
I'm slightly confused about runtime polymorphism. Correct me if I am wrong, but to my knowledge, runtime polymorphism means that function definitions will get resolved at runtime.
Take this example:
class a
{
a();
~a();
void baseclass();
}
class b: class a
{
b();
~b();
void derivedclass1();
}
class c: class a
{
c();
~c();
void derivedclass2();
}
Calling methodology:
b derived1;
a *baseptr = &derived1; //here base pointer knows that i'm pointing to derived class b.
baseptr->derivedclass1();
In the above calling methodology, the base class knows that it's pointing to derived class b.
So where does the ambiguity exist?
In what cases will the function definitions get resolved at runtime?
This code, at run time, calls the correct version of f() depending on the type of object (A or B) that was actually created - no "ambiguity". The type cannot be known at compile-time, because it is selected randomly at run-time.
struct A {
virtual ~A() {}
virtual void f() {}
};
struct B : public A {
virtual void f() {}
};
int main() {
A * a = 0;
if ( rand() % 2 ) {
a = new A;
}
else {
a = new B;
}
a->f(); // calls correct f()
delete a;
}
There is no ambiguity exists in the example provided.
If the base class has the same function name as the derived class, and if you call in the way you specified, it will call the base class's function instead of the derived class one.
In such cases, you can use the virtual keyword, to ensure that the function gets called from the object that it is currently being pointed. It is resolved during the run time.
Here you can find more explanation..
Turn this
void baseclass();
to
virtual void baseclass();
Override this in your Derived classes b and c. Then
b *derived1 = new derived1 ();
a *baseptr = derived1; //base pointer pointing to derived class b.
baseptr->baseclass();
will invoke derived1 definition, expressing run time polymorphism. And do remember about making your destructor virtual in Base. Some basic reading material for polymorphism
Runtime means that exact method will be known only at run time. Consider this example:
class BaseClass
{
public:
virtual void method() {...};
};
class DerivedClassA : public BaseClass
{
virtual void method() {...};
};
class DerivedClassB : public BaseClass
{
virtual void method() {...};
};
void func(BaseClass* a)
{
a->method();
}
When you implement your ::func() you don't know exactly type of instance pointed by BaseClass* a. It might be DerivedClassA or DerivedClassB instance etc.
You should realize, that runtime polymorphism requires special support from language (and maybe some overhead for calling "virtual" functions). In C++ you "request" for dynamic polymorphism by declaring methods of base class "virtual" and using public inheritance.
You need to have some useful business method declared in the base and in each derived class. Then you have code such as
a->someMethod();
Now the a pointer might point to an instance of any of the derived classes, and so the type of what a is pointing to must determine which someMethod() is called.
Lets have an experiment
#include <iostream>
using namespace std;
class aBaseClass
{
public:
void testFunction(){cout<<"hello base";}///Not declared as virtual!!!!
};
class aDerivedClass:public aBaseClass
{
public:
void testFunction(){cout<<"hello derived one";}
};
class anotherDerivedClass:public aDerivedClass
{
public:
void testFunction(){cout<<"hello derived two";}
};
int main()
{
aBaseClass *aBaseClassPointer;
aBaseClassPointer=new aDerivedClass;
aBaseClassPointer->testFunction();
}
The above code does not support run time polymorphism. Lets run and analyze it.
The output is
hello base
Just change the line void testFunction(){cout<<"hello base";} to virtual void testFunction(){cout<<"hello base";} in aBaseClass. Run and analyze it. We see that runtime polymorphism is achieved. The calling of appropriate function is determined at run time.
Again change the line aBaseClassPointer=new aDerivedClass to aBaseClassPointer=new anotherDerivedClass in main function and see the output. Thus the appropriate function calling is determined at run time (when the program is running).