Does passing by reference always avoid the slicing issue? - c++

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.

Related

passing reference argument to function taking universal reference of unique_ptr

I have two functions whose signatures I can't change. The first one takes a reference to an object, while the second takes a universal reference to a unique pointer of the same object. I'm not sure how to pass the first argument to the second.
I've tried by passing a new unique ptr with the address of the reference, but because the reference is abstract, the compiler complains about the unimplemented methods.
Here is an example:
// Example program
#include <iostream>
#include <memory>
class MyAbstractClass {
public:
virtual void doSomething() = 0;
};
class MyConcreteClass : public MyAbstractClass {
public:
void doSomething() override {
std::cout << "Hello I do something" << std::endl;
}
};
class MyUserClass {
public:
MyUserClass(MyAbstractClass& mac){
// the line below doesn't work !!
doSomethingElse(std::make_unique<MyAbstractClass>(&mac));
}
void doSomethingElse(std::unique_ptr<MyAbstractClass>&& mac){
mac->doSomething();
}
};
int main() {
MyConcreteClass mcc;
MyUserClass muc(mcc);
}
Your compiler complains because make_unique calls new on the type you are trying to instantiate, effectively copying the existing object. Of course, it can't do that, as the class is abstract.
Unless you have a way to guarantee that the reference passed to MyUserClass is to a dynamic ("heap") variable (and its pointer is not owned, etc.), you cannot just capture its pointer in unique_ptr and then release it after doSomethingElse. Even if this is guaranteed, for all you know, doSomethingElse could still try to delete the pointer itself (unless you know exactly what it does). As you pass it by rvalue reference, the object may not as well be valid after doSomethingElse returns.
That means you have to make a copy of the object. You can't make a plain copy though. You need to do a copy of the entire, non-abstract, underlying object.
If you are allowed to change signature of the classes, adding a virtual clone method would to the trick.
If not, a not-absolutely-terrible workaround could be (you need to know beforehand all the types that inherit MyAbstractClass though) switch(typeid(mac)) and dynamic_cast.

How can I call a method of derivitive class within base's class constructor using a pointer to function?

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.)

Dereferencing upcasted member function pointers

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).

member variable polymorphism & argument by reference

I'm new to C++ and have a question about member variable polymorphism. I have the following class definitions -
class Car
{
public:
Car();
virtual int getNumberOfDoors() { return 4; }
};
class ThreeDoorCar : public Car
{
public:
ThreeDoorCar();
int getNumberOfDoors() { return 3; }
};
class CarPrinter
{
public:
CarPrinter(const Car& car);
void printNumberOfDoors();
protected:
Car car_;
};
and implementation
#include "Car.h"
Car::Car()
{}
ThreeDoorCar::ThreeDoorCar()
{}
CarPrinter::CarPrinter(const Car& car)
: car_(car)
{}
void CarPrinter::printNumberOfDoors()
{
std::cout << car_.getNumberOfDoors() << std::endl;
}
The problem is when I run the following, the getNumberOfDoors of the parent class is called. I can get around this issue by making the member variable Car a pointer, but I prefer to pass in the input by reference instead of by pointer (which I understand to be preferred). Could you tell me what I'm doing wrong? Thanks!
ThreeDoorCar myThreeDoorCar;
std::cout << myThreeDoorCar.getNumberOfDoors() << std::endl;
CarPrinter carPrinter(myThreeDoorCar);
carPrinter.printNumberOfDoors();
By making a copy of the object you sacrifice its polymorphic abilities. Whatever type of car you pass, the copy will be of type Car (the base class), because that is what it is declared as.
If you want to keep using polymorphism either use a pointer or a reference. Here is the version using a reference:
class CarPrinter
{
public:
CarPrinter(const Car& car);
void printNumberOfDoors();
protected:
const Car &car_; // <<= Using a reference here
};
As you can see, this way you can continue using a constructor that takes a reference as argument. (These references don't have to be const, although const makes sense as long as the purpose of the CarPrinter is just printing.)
One potentially undesirable side-effect of this is that you can't change what the reference refers to after constructing the CarPrinter object. If you need to print the information for a different object, you'll have to create a new CarPrinter object for that. These objects would then really just act as (probably short-lived) wrappers around references.
If you don't like this, you can still continue passing a reference to the constructor, but turn it into a pointer by taking its address in the constructor implementation and then storing that.
When you do:
Car m_car;
It will not treat the m_car instance polymorphically, even if Car has subclasses and virtual functions. It will just use Car functions. This is called static binding - it determines which function to call at compile time based on the static type (Car) .
You need a reference or pointer for it to be handled polymorphically via dynamic dispatch by looking up the correct virtual function via the virtual function table of the instance's dynamic type (e.g. ThreeDoorCar or TwoDoorCar etc) at runtime. Polymorphic call behaviour is achieved through pointers or references in combination with virtual function declarations. This is more or less a direct result of syntactically using values vs pointers/refs (See #kfmfe04's comment below).
Car* pCar;
Car& rCar = x_car;
Virtual members called via a pointer or reference (e.g. pCar->getNumberOfDoors() or rCar.getNumberOfDoors()) does a vtable lookup at run time (dynamic dispatch). Because only at runtime does it know the dynamic type of the instance.
But m_car.getNumberOfDoors() is a virtual member that is called directly, and the compiler knows at compile time the direct (static) type and function address, statically binding the function address (Car::getNumberOfDoors) at compile time.
The problem is in this line of the CarPrinter constructor:
: car_(car)
This calls the compiler generated default copy constructor for the Car class, which ends up creating an instance of Car, not ThreeDoorCar.
Unfortunately, you'd need to pass the pointer, or pass by reference, but store the pointer. For example:
class CarPrinter
{
public:
CarPrinter(const Car& car)
:car_(&car) {};
...
protected:
const Car* car_;
};

Passing "this" to a function from within a constructor?

Can I pass "this" to a function as a pointer, from within the class constructor, and use it to point at the object's members before the constructor returns?
Is it safe to do this, so long as the accessed members are properly initialized before the function call?
As an example:
#include <iostream>
class Stuff
{
public:
static void print_number(void *param)
{
std::cout << reinterpret_cast<Stuff*>(param)->number;
}
int number;
Stuff(int number_)
: number(number_)
{
print_number(this);
}
};
void main() {
Stuff stuff(12345);
}
I thought this wouldn't work, but it seems to. Is this standard behavior, or just undefined behavior going my way?
When you instantiate an object in C++, the code in the constructor is the last thing executed. All other initialization, including superclass initialization, superclass constructor execution, and memory allocation happens beforehand. The code in the constructor is really just to perform additional initialization once the object is constructed. So it is perfectly valid to use a "this" pointer in a class' constructor and assume that it points to a completely constructed object.
Of course, you still need to beware of uninitialized member variables, if you haven't already initialized them in your constructor code.
You can find a good answer to this here (C++ FAQ).
All inherited members and members of the calling class are guaranteed to have been constructed at the start of the constructor's code execution and so can be referenced safely within it.
The main gotcha is that you should not call virtual functions on this. Most times I've tried this it just ends up calling the base class's function, but I believe the standard says the result is undefined.
As a side-note on the presented code, I would instead templatize the void*:
class Stuff
{
public:
template <typename T>
static void print_number(const T& t)
{
std::cout << t.number;
}
int number;
Stuff(int number_)
: number(number_)
{
print_number(*this);
}
};
Then you'd get a compile error if the type of t doesn't have a number member.
Andy, I think you're wrong about the undefined part of the standard.
When you're in the constructor, "this" is a pointer to an object whose type is the base class of the object you're creating, which means that virtual functions partially implemented in the base class will be called and the pointers in the virtual table won't be followed.
More info in the C++ Faq Lite...