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.
Related
Case where the problem occours
Please consider the following c++ code:
#include <functional>
#include <iostream>
#include <string>
// Superclass
class A {
public:
virtual std::string get() const {
return "A";
}
};
// Subclass
class B : public A {
public:
virtual std::string get() const {
return "B";
}
};
// Simple function that prints the object type
void print(const A &instance) {
std::cout << "It's " << instance.get() << std::endl;
}
// Class that holds a reference to an instance of A
class State {
A &instance;
public:
State(A &instance) : instance(instance) { }
void run() {
// Invokes print on the instance directly
print(instance);
// Creates a new function by binding the instance
// to the first parameter of the print function,
// then calls the function.
auto func = std::bind(&print, instance);
func();
}
};
int main() {
B instance;
State state(instance);
state.run();
}
In this example, we have two classes A and B. B inherits from class A. Both classes implement a simple virtual method that returns the type name.
There is also a simple method, print, that accepts a reference to an instance of A and prints the type.
The class State holds a reference to an instance of A. The class also has a simple method that calls print by two different means.
Where it gets odd
The sole method in state first calls print directly. Since we supply an instance of B int the main method, the output is It's B, as expected.
For the second call, however, we bind the instance to the first parameter of print using std::bind. Then we call the resulting function without any arguments.
In this case, however, the output is It's A. I would have expected the output It's B, as before, since it is still the same instance.
If I declare the parameters as pointers instead of references, std::bind works as expected. I also placed some logging into the constructors of both classes to verify that no instances are created accidentally.
Why does this happen? Does std::bind discard some type information in this case? To my understanding, this must not happen since the method invocation should be managed by a vtable lookup via runtime.
This is just object slicing. Pass the instance by reference:
auto func = std::bind(&print, std::ref(instance));
// ^^^^^^^^
To explain this a bit more: Like most C++ standard library types, the result type of a bind expression owns all its bound state. This means you can take this value and pass it around freely and store it and come back to it later in a different context, and you can still call it with all its bound state ready for action.
Therefore, in your code, the bind object was constructed with a copy of instance. But since instance wasn't a complete object, you caused slicing to happen.
By contrast, my code copies a std::reference_wrapper<A> into the bind object, and that's essentially a pointer. It doesn't own the instance object, so I need to keep it alive as long as the bind object may get called, but it means that the bound call is dispatched polymorphically to the complete object.
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).
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_;
};
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.
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...