I have the following switch statement in C++ where BaseType
is an abstract class:
switch (foo)
{
case 1:
{
DerivedType t = SomeDerivedType(); //Instantiate some derived type.
FunctionThatTakesBaseType(t); //Pass it to this function.
break;
}
case 2:
{
SomeOtherDerivedType t = SomeOtherDerivedType(); //Instantiate some other dervied type.
FunctionThatTakesBaseType(t) //Pass it to the same function.
break;
}
case 3:
{
...
}
}
If this were C#, I'd write this more succinctly by declaring a base type variable outside of the switch statement, defining it in the switch, and calling the function just once after the switch, like this:
BaseType t; //Declared outside of scope of the switch so I can call the function once afterward.
switch (foo)
{
case 1:
t = new SomeDerivedType();
break;
case 2:
t = new SomeOtherDerivedType();
break;
case 3:
...
}
FunctionThatTakesBaseType(t);
Is there a way to do this in C++? How do you declare an abstract type variable in an outer scope and define it with a concrete type in an inner scope? Is there a way to write C++ code as briefly as the C# code? You can't do this:
Base t; //ERROR: In C++ this attempts to instantiate the abstract base class!
And it seems like you can't do this:
Base* t; //OK, but to assign the variable inside the switch do you have to allocate the
//object on the heap?
Yes, you do have to use a pointer and heap allocation.
BaseType *t;
switch (foo)
{
case 1:
t = new SomeDerivedType();
break;
case 2:
t = new SomeOtherDerivedType();
break;
case 3:
...
}
You might also consider using a smart pointer. E.g.
std::unique_ptr<BaseType> t;
switch (foo)
{
case 1:
t = std::make_unique<SomeDerivedType>();
break;
case 2:
t = std::make_unique<SomeOtherDerivedType>();
break;
case 3:
...
}
This is exactly what's happening in languages where all objects are allocated on the heap.
Stack allocation relies on knowing the size of an object. A virtual base class doesn't indicate the size of the derived class. Consider:
struct X {
virtual std::string to_string() = 0;
};
struct Y : public X {
std::string mem_var;
Y(std::string m) : mem_var(m) { }
std::string to_string() override {
return mem_var;
}
};
struct Z : public X {
std::string to_string() override {
return "Z";
}
}
Do instances of Y
and Z
require the same amount of memory?