Let's say I have 2 classes Instrument and Brass, where Brass is derived from Instrument:
class Instrument
{
protected:
std::string _sound;
public:
Instrument(std::string sound) : _sound(sound) {}
virtual void play() { std::cout << _sound << std::endl; }
};
class Brass : public Instrument
{
private:
std::string _pitchShifter;
public:
Brass(std::string pitchShifter) : Instrument("braaaaaa"), _pitchShifter(pitchShifter)
{}
void printPitchShifter() { std::cout << _pitchShifter << std::endl; }
}
For some crazy reason I have a pointer to a member function of Instrument:
typedef void(Instrument::*instrumentVoidFunc)() //declaring member function pointers is too damn confusing
instrumentVoidFunc instrumentAction;
Now obviously, this will work, with well-defined behaviour:
Instrument soundMaker("bang!");
instrumentAction = &Instrument::play;
(soundMaker.*instrumentAction)();
And the output should be bang!.
But I can also make instrumentAction point to a Brass member function not present in Instrument by upcasting it, like so:
instrumentAction = static_cast<instrumentVoidFunc>(&Brass::printPitchShifter);
My understanding is (or was, anyway) that upcasting the member function pointer should destroy any ability for it to refer to derived class functions that aren't already present in the base class. However:
Brass trumpet("valves");
(trumpet.*instrumentAction)();
...prints out valves just as if I had called the function on the derived class normally. So apparently upcasting a derived class function pointer does not affect what happens when it is dereferenced on a derived class (though dereferencing it on a base class gives undefined behaviour).
How exactly does the compiler make this possible?
Although function pointer casts are possible, calling a function through a function type which doesn't match the original type is undefined behavior. The reason function pointer casts are allowed is to support casting to and storing a common type but recovering the correct by casting the function pointer back before calling it. The basic background for this restriction is that even compatible pointers may require adjustment upon use. Hiding the correct signature would imply a suitable trampoline to exist (i.e., the function pointer would need to have additional state).
Related
Disclaimer: I am a C developer and it's my first time that I'm trying something like this in C++. I have zero experience with the language.
I have a class Bob that has a pointer to a function myFunction as a private member.
I want to inherit the class Bob and pass a method of the derived class to the pointer function using the base class constructor.
This is my code:
#include <iostream>
using FuncHandler = void (*)(int x);
class Bob
{
protected:
Bob(FuncHandler x)
{
myFunction = x;
// When I call the function here
// I get garbage...
// x value is = 932452288
myFunction(10);
}
private:
FuncHandler myFunction;
};
class Alice : public Bob
{
public:
Alice() : Bob(reinterpret_cast<FuncHandler>(&Alice::foo))
{
}
void foo(int x);
};
void Alice::foo(int x)
{
std::cout << "x value is = " << x << "\n";
}
int main(void)
{
Alice obj1;
return 0;
}
The question is what did I do wrong that I'm getting garbage to the output?
The using FuncHandler = void (*)(int x); is a convenient name for a function pointer.
Alice's void foo(int x); is not a function, it's a member function. A member function is a different kind of thing than a freestanding function.
Fortunately, in this particular case, the code does not need to access the function as Alice's member function, it can use a static class function, which is compatible with a function pointer. Assuming the signatures match, which in this case they do.
Change void foo(int x); to static void foo(int x);.
Then change Alice() : Bob(reinterpret_cast<FuncHandler>(&Alice::foo)) to Alice() : Bob(&Alice::foo) and the code is all set.
CAUTION: if the foo function needed to access Alice's instance state, it would have problems because at that construction point in the code the Alice object has not been constructed yet.
I see two major issues with your approach.
First, base classes are constructed before derived classes. Inside the base class constructor, the derived class does not yet exist, so calling a non-static member function of the derived class is undefined behavior.
Second, your functional cast is invalid. It works in one sense, but the converted value cannot be used safely. Whenever you feel the need to use reinterpret_cast, don't; use static_cast or dynamic_cast instead. While there are some valid uses for reinterpret_cast, beginners tend to use it in bad locations. The static and dynamic casts are powerful enough for most needs and weak enough to fail when you try to do something inappropriate, such as your conversion. (Pointer-to-member-function is a different beast than pointer-to-function. While the compiler might allow converting one to the other, it is not safe to invoke the function through the converted value.)
You possibly should go back to the drawing board. At the very least, remember to mark member functions static if they do not use the this pointer. You might be letting your C background cloud your C++ thinking. (Of course, that is guesswork since I do not know your real problem.)
The code below works, but I'm not quite sure I understand why the member function pointer memfunc_ptr ends up pointing to the correct function Derived::member_func() (see example here). I know that a member function pointer defines an offset into the class of the object, for which it's defined, in this case class Base. So, to justify the result obtained by the code, i.e., that the member function Derived::member_func is called, instead of Base::member_func, I have to conclude that this offset is applied to the vtable of the class Derived, as member_func() is virtual, and the object d is of class Derived. Does that make sense?
#include <iostream>
class Base {
public:
virtual void member_func() {
std::cout << "Base" << '\n'; };
};
class Derived : public Base {
public:
virtual void member_func() { std::cout << "Derived" << '\n'; };
};
int main() {
typedef void (Base::*MFP)();
MFP memfunc_ptr;
memfunc_ptr = &Base::member_func;
Derived d;
(d.*memfunc_ptr)();
}
member_func() is a virtual function. The compiler will hence always call the most appropriate function for the real type of the object that is pointed to. The way this is ensured is implementation specific.
The most frequently way to do it is to use a vtable, a table of funtion pointers. A pointer to the vtable is initialised during the construction of the object. Every time you refer to such a virtual function, the compiler will generate code to find the function pointer in the vtable (using an ofset in the vtable). And when you use a pointer to a virtual function, the compiler will generate code to find the right pointer in the vtable.
This article will show you how this work with more details.
I have a cpp code where in class c is derived from class b and class b is derived from class a.
Now class b has some public data member. So I am creating a instance of class c on heap passing its pointer to another class as pointer to a and there it is downcasting that pointer to pointer of class b and then printing public variables of class b.
Is this a valid downcasting. I am asking because just change of compiler has broken this working code.
I am including below code snippet which captures problem I am having.
#include <iostream>
using namespace std;
class grand
{
};
class parent : public grand
{
public : parent(){i=0;}
int i;
parent(int j){ i = j;}
void set(int j){i = j;}
};
class child : public parent{
public: child(){};
};
void print ( grand* ptr)
{
parent *p = (parent*) ptr;
std::cout << std::endl << p->i << std::endl;
}
int main() {
// your code goes here
child c;
c.set(9);
print(&c);
return 0;
}
Thanks
Is this a valid downcasting.
Yes. Your cast internally applies static_cast, which, according to ยง5.2.9/11, will give you the right result. If the argument for ptr doesn't point to a parent, the result of the cast is undefined - and so would the execution of the following code be.
Downcasting of polymorphic types in C++ works via dynamic_cast. Your grand class above isn't polymorphic - you have to add at least a virtual destructor to grand to make it polymorphic. Otherwise you'll get a compiler error with the following code.
parent *p = dynamic_cast<parent*>(ptr); // Once grand is polymorphic...
And check whether the result, p, is non-zero. Only this method reveals (at runtime) whether the cast worked! All others either invoke undefined behavior or undefined, non-zero values.
Some notes:
Downcasting is almost always a sign of bad design. Avoid it if possible, using - for example - virtual (print) functions.
print should take a pointer to const since it doesn't modify any data members.
Your code, as written, is in fact valid, but there are a bunch of observations I'd like to make. Note that it's valid only because the object you pass to print is a parent or further derived class.
Then note that since you have to cast it the print function it's much safer to just change the function signature to take aparent instead of a grand and then you don't have to worry about the casting.
Then note that a likely cause of your problem is that in the file that does the cast, the compiler doesn't see the relationship between grand and parent so your C-style cast falls back to reinterpret_cast which is not what you want. If you can't change the signature of print at least change the cast to static_cast (or possibly dynamic_cast, but you can't do that in your example because the classes aren't polymorphic) so that the compiler will fail to compile when it can't see the class relationship.
Instead of a C-style cast you should apply a dynamic_cast or a at least a static_cast if you compile without RTTI (runtime type information) for some reason.
Your C-style cast is the same as a reinterpret_cast, which essentially interprets the memory pointed to as if an object of type parent would have been constructed there. But, every compiler may have a different memory layout of derived classes, thus that may work in some circumstances but there's no guarantee.
I was studying Virtual Functions and Pointers. Below code made me to think about, why does one need Virtual Function when we can type cast base class pointer the way we want?
class baseclass {
public:
void show() {
cout << "In Base\n";
}
};
class derivedclass1 : public baseclass {
public:
void show() {
cout << "In Derived 1\n";
}
};
class derivedclass2 : public baseclass {
public:
void show() {
cout << "In Derived 2\n";
}
};
int main(void) {
baseclass * bptr[2];
bptr[0] = new derivedclass1;
bptr[1] = new derivedclass2;
((derivedclass1*) bptr)->show();
((derivedclass2*) bptr)->show();
delete bptr[0];
delete bptr[1];
return 0;
}
Gives same result if we use virtual in base class.
In Derived 1
In Derived 2
Am I missing something?
Your example appears to work, because there is no data, and no virtual methods, and no multiple inheritance. Try adding int value; to derivedclass1, const char *cstr; to derivedclass2, initialize these in corresponding constructors, and add printing these to corresponding show() methods.
You will see how show() will print garbage value (if you cast pointer to derivedclass1 when it is not) or crash (if you cast the pointer to derivedclass2 when class in fact is not of that type), or behave otherwise oddly.
C++ class member functions AKA methods are nothing more than functions, which take one hidden extra argument, this pointer, and they assume that it points to an object of right type. So when you have an object of type derivedclass1, but you cast a pointer to it to type derivedclass2, then what happens without virtual methods is this:
method of derivedclass2 gets called, because well, you explicitly said "this is a pointer to derivedclass2".
the method gets pointer to actual object, this. It thinks it points to actual instance of derivedclass2, which would have certain data members at certain offsets.
if the object actually is a derivedclass1, that memory contains something quite different. So if method thinks there is a char pointer, but in fact there isn't, then accessing the data it points to will probably access illegal address and crash.
If you instead use virtual methods, and have pointer to common base class, then when you call a method, compiler generates code to call the right method. It actually inserts code and data (using a table filled with virtual method pointers, usually called vtable, one per class, and pointer to it, one per object/instance) with which it knows to call the right method. So when ever you call a virtual method, it's not a direct call, but instead the object has extra pointer to the vtable of the real class, which tells what method should really be called for that object.
In summary, type casts are in no way an alternative to virtual methods. And, as a side note, every type cast is a place to ask "Why is this cast here? Is there some fundamental problem with this software, if it needs a cast here?". Legitimate use cases for type casts are quite rare indeed, especially with OOP objects. Also, never use C-style type casts with object pointers, use static_cast and dynamic_cast if you really need to cast.
If you use virtual functions, your code calling the function doesn't need to know about the actual class of the object. You'd just call the function blindly and correct function would be executed. This is the basis of polymorphism.
Type-casting is always risky and can cause run-time errors in large programs.
Your code should be open for extension but closed for modifications.
Hope this helps.
You need virtual functions where you don't know the derived type until run-time (e.g. when it depends on user input).
In your example, you have hard-coded casts to derivedclass2 and derivedclass1. Now what would you do here?
void f(baseclass * bptr)
{
// call the right show() function
}
Perhaps your confusion stems from the fact that you've not yet encountered a situation where virtual functions were actually useful. When you always know exactly at compile-time the concrete type you are operating on, then you don't need virtual functions at all.
Two other problems in your example code:
Use of C-style cast instead of C++-style dynamic_cast (of course, you usually don't need to cast anyway when you use virtual functons for the problem they are designed to solve).
Treating arrays polymorphically. See Item 3 in Scott Meyer's More Effective C++ book ("Never treat arrays polymorphically").
This surprised me a little bit, but I was playing around with some code and found out that, at least on my computer, when a function accepts a parent class by reference and you pass a child instance, that the slicing problem doesn't occur. To illustrate:
#include <iostream>
class Parent
{
public:
virtual void doSomething()
{
using namespace std;
cout << "Parent::DoSomething" << endl;
}
};
class Child : public Parent
{
public:
virtual void doSomething()
{
using namespace std;
cout << "Child::DoSomething" << endl;
}
};
void performSomething(Parent& parent)
{
parent.doSomething();
}
int main(int argc, char** argv)
{
Child myChild;
performSomething(myChild);
return 0;
}
This prints out Child::DoSomething.
Like I said, I was a little surprised. I mean, I know that passing by reference is like passing pointers around (but much safer in my understanding), but I didn't know I still got to keep polymorphic goodness when doing so.
I just want to make sure, is this supposed to happen or is it one of those "it works on my machine" type of instances?
"Slicing" refers to the inability of the base copy constructor to distinguish exact type matches from derived classes. The only way to invoke slicing is to invoke the base copy constructor. Typically this occurs when passing arguments by value, though other situations can be contrived:
class Base { };
class Derived : public Base { };
void foo(Base);
int main()
{
Derived x;
Base y = x; // flagrant slicing
foo(x); // slicing by passing by value
}
You're never doing any such thing, so you do not encounter any slicing situations.
The behavior you are seeing is correct. This is how it is supposed to work. References work just like pointers.
That's supposed to happen. Passing by reference is EXACTLY like passing pointers -- it's doing the same thing under the hood. There's no magic to this; every instance of a polymorphic object has a virtual function table associated with it. As long as you don't copy anything, you're not going to lose that information and your virtual function calls will work the way you expect they would.
The reason that you run into problems when passing by value is that it will use the copy constructor of the type you specified in the function signature, so you end up with an entirely new instance of the superclass.
Yes, binding to a reference enables dynamic binding. This is caused by the difference of the dynamic type of an object and its static type.
If you take your parameter by value, it becomes a Parent class. Although if you pass something through a reference or a pointer and call a virtual function, the run-time will look for the dynamic type or most-derived type of the actual object that is being referenced.