#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
The above foo call is a compile time error.
I want to call foo with obj's B part without using virtual inheritance. How do i do that.
Also, in case of virtual inheritance, why the offset information need to be stored in the vtable. This can be determined at the compile time itself. In the above case, if we pass foo with D's object, at compile time only we can calculate the offset of D's A part.
Inheriting twice
With double inheritance you have an ambiguity - the compiler cannot know which of the two A bases do you want to use. If you want to have two A bases (sometimes you may want to do this), you may select between them by casting to B or C. The most appropriate from default casts here is the static_cast (as the weakest available), however it is not realy needed (it is still stronger than your case needs), as you are not casting to a derived type. A custom safe_cast template should do the job:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
Compile time types - use templates
Also, in case of virtual inheritance,
why the offset information need to be
stored in the vtable. This can be
determined at the compile time itself.
In the above case, if we pass foo with
D's object, at compile time only we
can calculate the offset of D's A
part.
This is a misconception. The foo function as it is written now has no compile type information about ptr type other than it is A *, even if you pass B * or C*. If you want foo to be able to act based on the type passed compile time, you need to use templates:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
Virtual Inheritance
Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify so:
class B: public virtual A ...
class C: public virtual A ...
With this the code would compile, but with this solution there is no way you could select between B::A or C::A (there is only one A), therefore this is probably not what you are about.
Virtual functions
Furthermore, your questions seems to be confusing two different concepts, virtual inheritance (which means sharing one base class between two intermediate base classes) and virtual functions (which mean allowing derived class function to be called via base class pointer). If you want the B::eat to be called using A pointer, you can do this without virtual inheritance (actually virtual inheritance would prevent you doing so, as explained above), using virtual functions:
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
If virtual functions are not acceptable for you, the compile time mechanism for this are templates, as explained above.
Use a cast - static_cast is required here to cast up the heirarchy.
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
First of all, obj does not have a member named B. It Inherits from B, which means that it inherits all of B's members as its own.
You can call:
foo(static_cast<B*>(&obj)); to make it work.
I don't think the static_cast will work.
When you are on the foo function, all the compiler knows is that you have a pointer to A, whatever the type you passed as parameter.
If you don't use virtual inheritance, then I think there is no way to call a B function from a pointer to A.
Related
I have here this abstract base class called base_class defined as it follows:
class base_class
{
public:
virtual ~base_class() = 0 {}
virtual size_t area() const = 0;
protected:
base_class() {}
};
One derived class from with it:
template <typename T> class A : public base_class
{
public:
A();
~A();
size_t area() const;
void display();
(...) etc code
};
And another class still derived from it:
template <typename T> class B : public base_class
{
public:
B();
~B();
size_t area() const;
void set();
(...) etc code
};
Than I have this instantiation and function call:
base_class *p = new A<int>;
p->display();
delete p;
p = new B<float>;
p->set();
(...) code
As you might already have observed, is that the pointer p won't "see" display and set methods.
The question is: when using pointers of type base_class, is there a chance of letting a derived object call derived methods that are only defined in the class that it points to? Thus being able to access display and set methods without having to make them virtual in the base class.
Otherwise we would have to make 2 virtual functions in the base_class, display and set, and that's very inconvenient, because A doesn't have to inherit set method, and B the display method.
You can use dynamic_cast to downcast from base class to derived class, if could not determine the runtime type of the object.
base_class *p = new A<int>;
if (A<int> *pa = dynamic_cast<A<int> *>(p))
pa->display();
delete p;
p = new B<float>;
if (B<float> *pb = dynamic_cast<B<float> *>(p))
pb->set();
If the type of object could be confirmed at compile time, static_cast can do the cast too, but beware: You are telling the compiler that you know for a fact that what is being pointed to really is of that type. If you are wrong, then the cast cannot inform you of the problem (as could dynamic_cast, which would return a null pointer if the cast failed, or throw a std::bad_cast for a reference cast failure) and, at best, you will get spurious run-time errors and/or program crashes.
Anyway, the best practice should be rearrange the inheritance relationship, try to use virtual function, avoid downcasts.
I am not quite sure what you ultimately want to do but its not usually good practice to call a function from the derived class that is not virtual in the base class using a pointer to a base class. As was already mentioned, you can use type casting to achieve this, but you need to check if the dynamic_cast was possible before attempting to call the function.
Have you considered creating a pure virtual function in the base class such as:
public:
virtual void doIt() = 0;
Then you could implement this in the derived classes to call the function you want:
class A
{
void doIt()
{
display();
}
};
class B
{
void doIt()
{
set();
}
};
There's actually no way of accessing the members since for all the program knows it wouldn't have to be a derived class, and could just be the base class. This meaning casting as mentioned in the comments.
A pointer is simply an integer, for 32bit OS's it's a 32 bit int, for 64bit well i guess you could guess right? 64bit integer.
When it comes to typing pointers to actual classes and structures etc, it's up to the API to decide whether or not to display the function, it's more of a helper.
As for the program only knows it's a base class pointer you can only access it's variables. However if you are 100% sure what you are dealing with and you want to save performance here's something somewhat pseudo code.
typedef void (A::*func)(void*);
func f = &A::set;
base_classPointer->*f();
But to be safe and sound either from the beginning make the pointer of the actual class as it seems you will be sure of that it's actually an A class.
Or use yourself of the dynamic, static, casts.
if(B * b = static_cast or dynamic_cast<B*>(mypointer))
Now I do suggest that you use yourself of exact pointer types if you are completely sure of what it's going to be. Or use yourself of the casts. If you are really anxious about performance, try the simple delegate method.
In the artificial example below, if I static_cast to the base class, when I call the setSnapshot() function it still calls the actual object setSnapshot(). This is what I want to happen. My question is can I always rely on this to work?
In code I am working on, we have this class hierarchy and in the b class there are macros used which static cast to the b type. This is to downcast from a base type so that specialised function in b can be called.
#include <iostream>
class a {
};
class b: public a {
public:
virtual void setSnapshot() { std::cout << "setting b snapshot\n"; }
};
class c : public b {
public:
virtual void setSnapshot() { std::cout << "setting c snapshot\n"; }
};
int main() {
a* o = new c;
//specifically casting to b
static_cast<b*>(o)->setSnapshot(); //prints setting c snapshot - what I want to happen
delete o;
return 0;
}
The title suggests that you're misunderstanding what the case does. new c creates an object of type c, and it will remain a c until it's destructed.
If you were to cast it to an a, you'd create a copy. But yu're only casting pointers. That doesn't affect the original object. That's still a c, and that's why you end up calling c::setSnapshot().
As long as a function is virtual in the statically known type a call of it will go to the override that is most derived.
For single inheritance this can be understood as a search for an implementation up the base class chain, starting in the most derived class.
In practice, for C++, the dynamic search is not done, and the effect of the search is instead implemented as a simple table lookup.
struct A{
virtual void fun(){cout<<"A";}
};
struct B:public A{
void fun(){cout<<"B";}
};
struct C:public B{
void fun(){cout<<"C";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
return 0;
}
In the above code B::fun() is getting converted to virtual function implicitly as I have made A::fun() virtual. Can I stop this conversion?
If not possible what are the alternatives to make the above code print "BB" ?
A virtual function is virtual in all derived classes. There is no way to prevent this.
(ยง10.3/2 C++11) If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.
However, if you'd like to use the function that corresponds to the static, rather than the dynamic, type of a pointer (i.e., in your example, B::fun instead of C::fun, given that the pointer is declared as B*), then you can, at least in C++11, use the alias definition below to get access to the static (=compile-time) type:
template <typename Ptr>
using static_type = typename std::remove_pointer<Ptr>::type;
This is how you'd use this in main() (or anywhere else):
int main()
{
C c; B b1;
A *a = &b1;
a->fun();
B *b = &c;
/* This will output 'B': */
b->static_type<decltype(b)>::fun();
return 0;
}
If you do not want your derived classes to override the function then there is no reason why you should mark it virtual in base class. The very basis of marking a function virtual is to have polymorphic behavior through derived class function overidding.
Good Read:
When to mark a function in C++ as a virtual?
If you want your code to guard you against accidental overidding in derived classes.You can use the final specifier in C++11.
Yes, if you want to explicitly call a function in a specific class you can use a fully qualified name.
b->A::fun();
This will call the version of fun() belonging to A.
The following achieves the observable behaviour you're asking for. In A, non-virtual fun() run virtual fun_() so the behaviour can be customised in B, but anyone calling fun() on a derived class will only see the non-polymorphic version.
#include <iostream>
using namespace std;
struct A{
void fun(){fun_();}
private:
virtual void fun_() { cout << "A\n"; }
};
struct B:public A{
void fun(){cout<<"B\n";}
private:
virtual void fun_() final { fun(); }
};
struct C:public B{
void fun(){cout<<"C\n";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
c.fun(); // notice that this outputs "C" which I think is what you want
}
If using C++03, you can simply leave out the "final" keyword - it's only there to guard against further unwanted overrides of the virtual behaviour in B-derived classes such as C.
(You might find it interesting to contrast this with the "Nonvirtual Interface pattern" - see C++ Coding Standards by Sutter and Alexandrescu, point 39)
Discussion
A having fun virtual implies that overriding it in derived classes is a necessary customisation ability for derived classes, but at some point in the derivation hierarchy the choice of implementation behaviours might have narrowed down to 1 and providing a final implementation's not unreasonable.
My real concern is that you hide A/B's fun() with C::fun... that's troubling as if they do different things then your code could be very hard to reason about or debug. B's decision to finalise the virtual function implies certainty that there's no need for such further customisation. Code working from A*/A&/B*/B& will do one thing, while wherever a C object's type is statically known, the behaviour may differ. Templated code is one place where C::fun may easily be called without the template author or user being very conscious of it. To assess whether this is a genuine hazard for you, it would help to know what the functional purpose of "fun" is and how implementation might differ between A, B and C....
If you declare the function in B like this
void fun(int ignored=0);
it will become an overload which will not take part in resolving virtual calls. Beware that calling a->fun() will call A::fun() though even if a actually refers to a B, so I would strongly advise against this approach as it makes things even more confusing than necessary.
Question is: What exactly is it that you want to achieve or avoid? Knowing that, people here could suggest a better approach.
conv.h
class Base
{
public:
void foo();
};
class Derived: public Base
{
public:
void bar();
};
class A {};
class B
{
public:
void koko();
};
conv.cpp
void Base::foo()
{
cout<<"stamm";
}
void Derived::bar()
{
cout<<"bar shoudn't work"<<endl;
}
void B::koko()
{
cout<<"koko shoudn't work"<<endl;
}
main.cpp
#include "conv.h"
#include <iostream>
int main()
{
Base * a = new Base;
Derived * b = static_cast<Derived*>(a);
b->bar();
Derived * c = reinterpret_cast<Derived*>(a);
c->bar();
A* s1 = new A;
B* s2 = reinterpret_cast<B*>(s1);
s2->koko();
}
output:
bar shoudn't work
bar shoudn't work
koko shoudn't work
How come the method bar is succeeded to be called in run time despite that I have created a Base class not derived?? it works even with two types of conversions (static and reinterpret cast).
same question as above but with unrelated classes (A & B) ??
Undefined behaviour can do anything, including appear to work.
It's working (read: "compiling and not crashing") 'cause you never use the this pointer in your nominally "member" functions. If you tried to print out a member variable, for example, you'd get the garbage output or crashes you expect - but these functions as they are now don't depend on anything in the classes they're supposedly part of. this could even be NULL for all they care.
The compiler knows a Derived can use member functions foo() and bar() and knows where to find them. After you did your "tricks", you had pointers to Derived.
The fact that they were pointers of type Derived -- regardless of what data was associated with those pointers -- allowed them to call the functions foo() and kook() associated with Derived.
As has been mentioned, if you had actually used the data at the pointers (i.e. read or wrote data members relative to this belonging to the Derived class (which you don't have in this case), you would have been access memory that didn't belong to your objects.
With the struct definition given below...
struct A {
virtual void hello() = 0;
};
Approach #1:
struct B : public A {
virtual void hello() { ... }
};
Approach #2:
struct B : public A {
void hello() { ... }
};
Is there any difference between these two ways to override the hello function?
They are exactly the same. There is no difference between them other than that the first approach requires more typing and is potentially clearer.
The 'virtualness' of a function is propagated implicitly, however at least one compiler I use will generate a warning if the virtual keyword is not used explicitly, so you may want to use it if only to keep the compiler quiet.
From a purely stylistic point-of-view, including the virtual keyword clearly 'advertises' the fact to the user that the function is virtual. This will be important to anyone further sub-classing B without having to check A's definition. For deep class hierarchies, this becomes especially important.
The virtual keyword is not necessary in the derived class. Here's the supporting documentation, from the C++ Draft Standard (N3337) (emphasis mine):
10.3 Virtual functions
2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
No, the virtual keyword on derived classes' virtual function overrides is not required. But it is worth mentioning a related pitfall: a failure to override a virtual function.
The failure to override occurs if you intend to override a virtual function in a derived class, but make an error in the signature so that it declares a new and different virtual function. This function may be an overload of the base class function, or it might differ in name. Whether or not you use the virtual keyword in the derived class function declaration, the compiler would not be able to tell that you intended to override a function from a base class.
This pitfall is, however, thankfully addressed by the C++11 explicit override language feature, which allows the source code to clearly specify that a member function is intended to override a base class function:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int) override; // ill-formed - doesn't override a base class method
};
The compiler will issue a compile-time error and the programming error will be immediately obvious (perhaps the function in Derived should have taken a float as the argument).
Refer to WP:C++11.
Adding the "virtual" keyword is good practice as it improves readability , but it is not necessary. Functions declared virtual in the base class, and having the same signature in the derived classes are considered "virtual" by default.
There is no difference for the compiler, when you write the virtual in the derived class or omit it.
But you need to look at the base class to get this information. Therfore I would recommend to add the virtual keyword also in the derived class, if you want to show to the human that this function is virtual.
The virtual keyword should be added to functions of a base class to make them overridable. In your example, struct A is the base class. virtual means nothing for using those functions in a derived class. However, it you want your derived class to also be a base class itself, and you want that function to be overridable, then you would have to put the virtual there.
struct B : public A {
virtual void hello() { ... }
};
struct C : public B {
void hello() { ... }
};
Here C inherits from B, so B is not the base class (it is also a derived class), and C is the derived class.
The inheritance diagram looks like this:
A
^
|
B
^
|
C
So you should put the virtual in front of functions inside of potential base classes which may have children. virtual allows your children to override your functions. There is nothing wrong with putting the virtual in front of functions inside of the derived classes, but it is not required. It is recommended though, because if someone would want to inherit from your derived class, they would not be pleased that the method overriding doesn't work as expected.
So put virtual in front of functions in all classes involved in inheritance, unless you know for sure that the class will not have any children who would need to override the functions of the base class. It is good practice.
There's a considerable difference when you have templates and start taking base class(es) as template parameter(s):
struct None {};
template<typename... Interfaces>
struct B : public Interfaces
{
void hello() { ... }
};
struct A {
virtual void hello() = 0;
};
template<typename... Interfaces>
void t_hello(const B<Interfaces...>& b) // different code generated for each set of interfaces (a vtable-based clever compiler might reduce this to 2); both t_hello and b.hello() might be inlined properly
{
b.hello(); // indirect, non-virtual call
}
void hello(const A& a)
{
a.hello(); // Indirect virtual call, inlining is impossible in general
}
int main()
{
B<None> b; // Ok, no vtable generated, empty base class optimization works, sizeof(b) == 1 usually
B<None>* pb = &b;
B<None>& rb = b;
b.hello(); // direct call
pb->hello(); // pb-relative non-virtual call (1 redirection)
rb->hello(); // non-virtual call (1 redirection unless optimized out)
t_hello(b); // works as expected, one redirection
// hello(b); // compile-time error
B<A> ba; // Ok, vtable generated, sizeof(b) >= sizeof(void*)
B<None>* pba = &ba;
B<None>& rba = ba;
ba.hello(); // still can be a direct call, exact type of ba is deducible
pba->hello(); // pba-relative virtual call (usually 3 redirections)
rba->hello(); // rba-relative virtual call (usually 3 redirections unless optimized out to 2)
//t_hello(b); // compile-time error (unless you add support for const A& in t_hello as well)
hello(ba);
}
The fun part of it is that you can now define interface and non-interface functions later to defining classes. That is useful for interworking interfaces between libraries (don't rely on this as a standard design process of a single library). It costs you nothing to allow this for all of your classes - you might even typedef B to something if you'd like.
Note that, if you do this, you might want to declare copy / move constructors as templates, too: allowing to construct from different interfaces allows you to 'cast' between different B<> types.
It's questionable whether you should add support for const A& in t_hello(). The usual reason for this rewrite is to move away from inheritance-based specialization to template-based one, mostly for performance reasons. If you continue to support the old interface, you can hardly detect (or deter from) old usage.
I will certainly include the Virtual keyword for the child class, because
i. Readability.
ii. This child class my be derived further down, you don't want the constructor of the further derived class to call this virtual function.