Forcing late method resolution in case of class inheritance in c++ - c++

Consider the following class structure:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.

Here's my comments as an answer.
You cannot do that.
If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?
If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.
If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
delete foo_pointer1;
delete foo_pointer2;
}

Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
If you'd like the main function, I've written a complete sample.

To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...
you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
so you can decide the output type later:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.

The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.

Related

How to do actions on members of child class templates from an abstact base class?

I know this question gets asked a lot, but I have a specific use case, so I don't think it's a duplicate!
I have an abstract base class:
template<int N>
class Child;
class Base
{
public:
// Factory-like generation of children as Base
static Ptr<Base> New(int baseN)
{
if (baseN == 2) return new Child<2>();
else if (baseN == 3) return new Child<3>()
}
// Update
virtual void update() = 0;
};
And I'm writing some children of Base as class templates (on an int):
template<int N>
class Child
:
public Base
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
// Implement update
virtual void update();
// Should call the passed callable on m_member
virtual void execute(std::function<void(Matrix<N>&)>&);
};
// Force compilation of Child<N> for some values of N (of interest, including 3) here
// Then,
int baseN = 3;
Ptr<Base> obj = Base::New(baseN); // will get me a Child<3> as a Base object
auto callable = [](Matrix<3>) ->void {};
// Can I access Child<3>::m_member ??
// Can't cast to Child<baseN> (baseN is not constexpr) and don't want to
// But want to do something like:
obj->execute(callable);
// Which forwards 'callable' to the method from concrete type, probably using a cast?
In short, I need to have some sort of access to m_member from the declared Base object.
Preferably, a way to call Child<N>::execute from Base without making Base a template on N too.
Things I've tried/thought-of include:
'Type erasure' of Matrix<N> by hiding them behind an interface, but because Matrix<N>'s interface strongly depends on N, doing that renders the classes useless (think: Vector<N>& Matrix<N>::diag() for example)
Can Base::New do anything to record what concrete type it creates? I doubt that because types are not objects.
EDIT: (Btw this is C++11)
So, I accidentally figured out a way to do this; but I don't quite understand why the following works (Not well versed into assembly yet):
I'm using a Database for objects (unordered_map<string, object*> where object is a class that every registered object has to inherit from).
When a Child is created, we register it to a database with a name of Child<N>.
Then, at application-level code, there is a findChild<int N> template which employs compile-time recursion to find which concrete class was the Base pointer created from (At runTime, by dynamicCasting and testing). When It finds it, it can cast it to void* through a static method (findChild<N>::castToConcrete)
What's interesting is that we can somehow use findChild<0> to access the findChild<N> in question if Child<N> is polymorphic. This forces us to have at most one object of Child (for all possible Ns) and I certainly can live with that.
You can see and inspect a minimal code example here: https://onlinegdb.com/CiGR1Fq5z
What I'm so confused about is that Child<0> and other Child<N> are completely different types; So how can we access one's members from a pointer to another type? I'm most likely relying on UB and even fear there is a stack smacking of some sort!
For reference, I'm including the code here in case the link dies.
#include <unordered_map>
#include <vector>
#include <functional>
#include <iostream>
using namespace std;
#ifndef MAX_N_VALUE
#define MAX_N_VALUE 10
#endif // !MAX_N_VALUE
// ------------------ Lib code
// A dummy number class for testing only
template <int N> struct Number { constexpr static int value = N; };
// Objects to register to the database
struct object
{
// Members
string name;
// construction/Destruction
object(const string& name) : name(name) {}
virtual ~object(){};
};
// Database of objects
struct DB
: public unordered_map<string, object*>
{
// See if we can the object of name "name" and type "T" in the DB
template <class T>
bool found(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return true;
cout << name << " found but it's of another type." << endl;
return false;
}
cout << name << " not found." << endl;
return false;
}
// Return a const ref to the object of name "name" and type "T" in the DB
// if found. Else, fails
template <class T>
const T& getObjectRef(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return *ptr;
cout << name << " found but it's of another type." << endl;
abort();
}
cout << name << " not found." << endl;
abort();
}
};
// Forward declare children templates
template<int N>
class Child;
// The interface class
struct Base
{
// Construction/Destruction
protected:
static unsigned counter;
Base(){}
public:
virtual ~Base() {}
// Factory-like generation of children as Base
// THIS New method needs to know how to construct Child<N>
// so defining it after Child<N>
static Base* New(int baseN, DB& db);
// Update
virtual void update() = 0;
// Call a callable on a child, the callable interface
// however is independent on N
virtual void execute(std::function<void(Base&)>& callable)
{
callable(*this);
}
};
unsigned Base::counter = 0;
// The concrete types, which we register to the DB
template<int N>
struct Child
:
public Base, public object
{
// members
vector<Number<N>> member;
// Construction/Destruction
Child() : Base(), object(string("Child") + to_string(N) + ">"), member(N, Number<N>()) {}
virtual ~Child() {}
// Test member method (Has to be virtual)
virtual vector<Number<N>> test() const
{
cout << "Calling Child<" << N << ">::test()" << endl;
return vector<Number<N>>(N, Number<N>());
}
// Implement update
virtual void update()
{
cout << "Calling Child<" << N << ">::update()" << endl;
};
};
// New Base, This can be much more sophisticated
// if static members are leveraged to register constructors
// and invoke them on demand.
Base* Base::New(int baseN, DB& db)
{
if (baseN == 2)
{
Child<2>* c = new Child<2>();
db.insert({string("Child<")+std::to_string(2)+">", c});
return c;
}
if (baseN == 3)
{
Child<3>* c = new Child<3>();
db.insert({string("Child<")+std::to_string(3)+">", c});
return c;
}
return nullptr;
}
// Finder template for registered children
template<int N>
struct findChild
{
// Concrete Type we're matching against
using type = Child<N>;
// Stop the recursion?
static bool stop;
// Compile-time recursion until the correct Child is caught
// Recursion goes UP in N values
static void* castToConcrete(const DB& db, Base* system)
{
if (N > MAX_N_VALUE) stop = true;
if (stop) return nullptr;
if (db.found<type>(string("Child<")+to_string(N)+">"))
{
type* ptr = dynamic_cast<type*>(system);
return static_cast<void*>(ptr);
}
// NOTE: This should jump to the next "compiled" child, not just N+1, but meh;
return findChild<N+1>::castToConcrete(db, system);
}
};
// Activate recursive behaviour for arbitraty N
template<int N>
bool findChild<N>::stop = false;
// Explicit specialization to stop the Compile-time recursion at a decent child
template<>
struct findChild<MAX_N_VALUE+1>
{
using type = Child<MAX_N_VALUE+1>;
static bool stop;
static void* castToConcrete(const DB& t, const Base* system)
{
return nullptr;
}
};
// Disactivate recursive behaviour for N = 11
bool findChild<MAX_N_VALUE+1>::stop = true;
// ------------------ App code
int main()
{
// Create objects database
DB db;
// --- Part 1: Application writers can't write generic-enough code
// Select (from compiled children) a new Base object with N = 2
// and register it to the DB
Base* b = Base::New(2, db);
b->update();
cout << "Access children by explicit dynamic_cast to Child<N>:" << endl;
// Get to the object through the objects DB.
// Child destructor should remove the object from DB too, nut meh again
const auto& oo = db.getObjectRef<Child<2>>("Child<2>");
cout << oo.test().size() << endl;
// --- Part 2: Application writers can write generic code if the compile
// Child<N> for their N
cout << "If Child<N> is polymorphic, we can access the correct child from findChild<0>:" << endl;
// Create a lambda that knows about db, which Base applies on itself
function<void(Base&)> lambda = [&db](Base& base) -> void {
// Cast and ignore the result
void* ptr = findChild<0>::castToConcrete(db, &base);
// Cast back to Child<0>
findChild<0>::type* c = static_cast<findChild<0>::type*>(ptr);
// Now access original Child<N> methods and members from Child<0>
cout << "Method:\n" << c->test().size() << endl;
cout << "Member:\n" << c->member.size() << endl;
};
b->execute(lambda);
return 0;
}
I compiled with GCC 9 with the following options:
-m64 -Wall -Wextra -Wno-unused-parameter -Wold-style-cast -Wnon-virtual-dtor -O0 -fdefault-inline -ftemplate-depth-200
It seems you want inheritance to group not so related classes...
std::variant (C++17) might be more appropriate:
template<int N>
class Child
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
void update();
void execute(std::function<void(Matrix<N>&)> f) { f(m_member); }
};
using Base = std::variant<Child<2>, Child<3>>;
and then:
void foo(Base& obj)
{
struct Visitor {
template <std::size_t N>
void operator()(Child<N>& c) const
{
auto callable = [](Matrix<N>) -> void {/*..*/};
c.execute(callable);
}
} visitor;
std::visit(visitor, obj);
}
To answer to your Edit, whereas your callable take a Base, you might chain the dynamic_cast as follow:
template <int N>
void foo_base(Base& b)
{
if (auto* child = dynamic_cast<Child<N>*>(&b)) {
// Job with Child<N>
std::cout << "Method:" << child->test().size() << std::endl;
std::cout << "Member:" << child->member.size() << std::endl;
}
}
template <int... Ns>
void foo_dispatch(std::integer_sequence<int, Ns...>, Base& base)
{
//(foo_base<Ns>(base), ...); // C++17
const int dummy[] = {0, (foo_base<Ns>(base), 0)...};
static_cast<void>(dummy); // Avoid warning about unused variable
}
With a call similar to:
function<void(Base&)> lambda = [](Base& base) {
//foo_dispatch(std::integer_sequence<int, 2, 3>(), base);
foo_dispatch(std::make_integer_sequence<int, MAX_N_VALUE>(), base);
};
Demo
(std::integer_sequence is C++14, but can be implemented in C++11)
Note: Jarod's answer is still a little bit better if you know possible
values of N in Child<N> at compile-time and don't want to provide a way to extend them. Plus, of course, if you can use C++17.
Here I'm relying on "Similar types" defined by the standard as:
4.4 Qualification conversions [conv.equal]
... trimmed ...
Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:
T1 is cv(1,0) pointer to cv(1,1) pointer to ··· cv(1,n−1) pointer to cv(1,n) T
and
T2 is cv(2,0) pointer to cv(2,1) pointer to ··· cv(2,n−1) pointer to (cv2,n) T
where each cv(i,j) is const, volatile, const volatile, or nothing
The same paragraph also shows the conditions for converting expressions.
In short, By inheriting from Base, all Child<N>* pointer types are similar to Base*, hence similar to each other.
Now, we know we can static_cast Child<N> to Child<0> without problems.
But is accessing Child<3> members from a Child<0>* safe?
3.10 Lvalues and rvalues [basic.lval]
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined:
the dynamic type of the object,
... trimmed ...
a type similar (as defined in 4.4) to the dynamic type of the object
There you have it, Accessing the values of Child<3> though a Child<0>* is in fact defined behavior.
This piece of code:
Base* b = Base::New(2);
b->update();
Child<2>* c1 = static_cast<Child<2>*>(b);
c1->update();
cout << c1->t.sValue << " " << c1->t.rValue << endl;
Child<0>* c2 = static_cast<Child<0>*>(b);
c2->update();
cout << c2->t.sValue << " " << c2->t.rValue << endl;
Will actually output (Note the value of the static variable Test<N>::sValue):
Calling Child<2>::update()
Calling Child<2>::update()
2 2
Calling Child<2>::update()
0 2
Static members will always point to Child<0>, and because of that,
Jarod's answer is a better solution for this problem.
But if one wants to allow expanding possible N values, this solution is OK; you just have to remember to put your static variables in Base and not in Child<N>.
Here is a minimal example, showing how to pass a lambda to the Base* while in fact the lambda, casts the pointer to Child<0> and operates on it:
https://onlinegdb.com/TTcMqOmWi

Modify object in base but return pointer to derived class

I have a kind of object registry where objects can be registered. This should be done in the initialization phase. E.g.
class ObjectBase {
protected:
bool active;
public:
void activate() { active = true; }
};
template<typename T>
class Object : public ObjectBase {
T value;
};
class Registry {
public:
template<typename T>
static std::shared_ptr<Object<T>> registerObject() {
return std::make_shared<Object<T>>();
}
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>();
}
Now I want the active value set at initialisation (and constructor parameters are not an option, as this is but one of many). What would be neat is if I were able to do the following:
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>()->activate();
}
However I don't see a way for activate() to return a pointer of type Object (unless I make it a template as well and do a dynamic cast, however this seems ugly), lest so a shared pointer. Or is there some way? Alternatively, do any of you have a recommendation how to approach this task (i.e. register something and set a number of properties)?
EDIT:
Naming my class Object may have been unfortunate. As a practical example, think of Object as a property (holding an integer). Obviously there may be multiple integer properties. And imagine "active" as something akin to "should be backed up" / "should be synced with a remote process" / ...
template<typename T>
std::shared_ptr< Object<T> > RegisterAndActivate() {
std::shared_ptr< Object<T> > p = Registry::registerObject<T>();
p->activate();
return p;
}
namespace {
std::shared_ptr< Object<int> > myObject = RegisterAndActivate<int>();
}
What about freestanding function(s):
template <typename T>
std::shared_ptr<Object<T>> activate(std::shared_ptr<Object<T>> ptr) {
ptr->activate();
return ptr;
}
Then
auto x = activate(Registry::registerObject<int>());
Ok, here's what I came up with:
#include <iostream>
#include <tuple>
#include <memory>
struct Test {
bool a;
bool b;
Test() : a(false),b(false) {};
};
template<typename T, bool T::* ... props>
std::shared_ptr<T> activate(std::shared_ptr<T> inst) {
std::tie((inst.get()->*props)...) = std::make_tuple((props,true)...);
return inst;
}
int main()
{
auto t1 = activate<Test,&Test::a>(std::make_shared<Test>());
auto t2 = activate<Test,&Test::a,&Test::b>(std::make_shared<Test>());
std::cout << "t1: a = " << t1->a << ", b = " << t1->b << std::endl;
std::cout << "t2: a = " << t2->a << ", b = " << t2->b << std::endl;
}
Basically, whatever pointers to bool members you specify as template parameters, those are going to be set to true by the activate function. This way, you don't have to write many activate functions, but it is still a lot of writing because of all the Classname::classmember expressions. Working example here.

Static polymorphism in C++

#include <iostream>
template<typename Impl>
struct renderer{
void get(){
static_cast<Impl*>(this)->get();
}
};
struct open_gl : public renderer<open_gl>{
void get(){
std::cout << "OpenGL" << std::endl;
}
};
struct direct_draw : public renderer<direct_draw>{
void get(){
std::cout << "DX" << std::endl;
}
};
template<typename T>
void print_renderer(renderer<T> r){
r.get();
}
int main() {
auto gl = open_gl();
auto dx = direct_draw();
print_renderer(gl);
print_renderer(dx);
}
Why can't I change the parameter of print_renderer to void
print_renderer(const renderer<T> &r)?
cannot convert 'this' pointer from 'const renderer<open_gl>' to 'renderer<open_gl> &'
`
Why do I get a runtime error when I rename the method get in open_gl from
get to get1? Shouldn't this trigger a compiler error? Error = Stack overflow
**Note I am using the latest MSVC
1) Because get is not a const member function : it cannot make the promise of not modify your (const) argument.
You could declare get as const, and it compiles fine :
void get() const { ... }
2) The base get method will be called, going into infinite recursion : Stack Overflow.
If you declare your function override (it needs to be virtual), the compiler will throw an error if it does not indeed override a base method :
void get1() override { ... } // Compiler error
void get() override { ... } // Ok
Note:
The title is "Static polymorphism in C++", but I think that you misunderstood what is static polymorphism : it does not (have to) make use of inheritance (as you did). Rather, the templates compile-time duck typing will statically "resolve" function calls for you.
That is, you don't need related types, you don't need the base renderer class at all, and you can simply do the following (in which case, renaming to get1 will cause a compiler error) :
#include <iostream>
struct open_gl {
void get(){
std::cout << "OpenGL" << std::endl;
}
};
struct direct_draw {
void get(){
std::cout << "DX" << std::endl;
}
};
template<typename T>
void print_renderer(T r){
r.get();
}
int main() {
auto gl = open_gl();
auto dx = direct_draw();
print_renderer(gl);
print_renderer(dx);
}
Live demo
Becuase get is not marked const.
Because the base class method is used (irrelevantly of cast), and it goes into infinite loop.

Changing VTBL of existing object "on the fly", dynamic subclassing

Consider the following setup.
Base class:
class Thing {
int f1;
int f2;
Thing(NO_INIT) {}
Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {}
virtual ~Thing() {}
virtual void doAction1() {}
virtual const char* type_name() { return "Thing"; }
}
And derived classes that are different only by implementation of methods above:
class Summator {
Summator(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 += f2; }
virtual const char* type_name() override { return "Summator"; }
}
class Substractor {
Substractor(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 -= f2; }
virtual const char* type_name() override { return "Substractor"; }
}
The task I have requires ability to change class (VTBL in this case) of existing objects on the fly. This is known as dynamic subclassing if I am not mistaken.
So I came up with the following function:
// marker used in inplace CTORs
struct NO_INIT {};
template <typename TO_T>
inline TO_T* turn_thing_to(Thing* p)
{
return ::new(p) TO_T(NO_INIT());
}
that does just that - it uses inplace new to construct one object in place of another. Effectively this just changes vtbl pointer in objects. So this code works as expected:
Thing* thing = new Thing();
cout << thing->type_name() << endl; // "Thing"
turn_thing_to<Summator>(thing);
cout << thing->type_name() << endl; // "Summator"
turn_thing_to<Substractor>(thing);
cout << thing->type_name() << endl; // "Substractor"
The only major problems I have with this approach is that
a) each derived classes shall have special constructors like Thing(NO_INIT) {} that shall do precisely nothing. And b) if I will want to add members like std::string to the Thing they will not work - only types that have NO_INIT constructors by themselves are allowed as members of the Thing.
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ? I have a feeling that std::move semantic may help to solve 'b' somehow but not sure.
Here is the ideone of the code.
(Already answered at RSDN http://rsdn.ru/forum/cpp/5437990.1)
There is a tricky way:
struct Base
{
int x, y, z;
Base(int i) : x(i), y(i+i), z(i*i) {}
virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};
int main()
{
Base b(3);
Base* p = &b;
b.whoami();
p->whoami();
assert(sizeof(Base)==sizeof(Derived));
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
printf("-----\n");
b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
p->whoami(); // here it calls virtual function, that is, Derived::whoami
d->whoami();
};
Of course, it's UB.
For your code, I'm not 100% sure it's valid according to the standard.
I think the usage of the placement new which doesn't initialize any member variables, so to preserve previous class state, is undefined behavior in C++. Imagine there is a debug placement new which will initialize all uninitialized member variable into 0xCC.
union is a better solution in this case. However, it does seem that you are implementing the strategy pattern. If so, please use the strategy pattern, which will make code a lot easier to understand & maintain.
Note: the virtual should be removed when using union.
Adding it is ill-formed as mentioned by Mehrdad, because introducing virtual function doesn't meet standard layout.
example
#include <iostream>
#include <string>
using namespace std;
class Thing {
int a;
public:
Thing(int v = 0): a (v) {}
const char * type_name(){ return "Thing"; }
int value() { return a; }
};
class OtherThing : public Thing {
public:
OtherThing(int v): Thing(v) {}
const char * type_name() { return "Other Thing"; }
};
union Something {
Something(int v) : t(v) {}
Thing t;
OtherThing ot;
};
int main() {
Something sth{42};
std::cout << sth.t.type_name() << "\n";
std::cout << sth.t.value() << "\n";
std::cout << sth.ot.type_name() << "\n";
std::cout << sth.ot.value() << "\n";
return 0;
}
As mentioned in the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ?
If you have fixed set of sub-classes then you may consider using algebraic data type like boost::variant. Store shared data separately and place all varying parts into variant.
Properties of this approach:
naturally works with fixed set of "sub-classes". (though, some kind of type-erased class can be placed into variant and set would become open)
dispatch is done via switch on small integral tag. Sizeof tag can be minimized to one char. If your "sub-classes" are empty - then there will be small additional overhead (depends on alignment), because boost::variant does not perform empty-base-optimization.
"Sub-classes" can have arbitrary internal data. Such data from different "sub-classes" will be placed in one aligned_storage.
You can make bunch of operations with "sub-class" using only one dispatch per batch, while in general case with virtual or indirect calls dispatch will be per-call. Also, calling method from inside "sub-class" will not have indirection, while with virtual calls you should play with final keyword to try to achieve this.
self to base shared data should be passed explicitly.
Ok, here is proof-of-concept:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
Output is:
Summator 12 7
Substractor 5 7
size: 2
LIVE DEMO on Coliru
Full Code (it uses some C++14 features, but can be mechanically converted into C++11):
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
#include <type_traits>
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
/****************************************************************/
// Boost.Variant requires result_type:
template<typename T, typename F>
struct ResultType
{
mutable F f;
using result_type = T;
template<typename ...Args> T operator()(Args&& ...args) const
{
return f(forward<Args>(args)...);
}
};
template<typename T, typename F>
auto make_result_type(F &&f)
{
return ResultType<T, typename decay<F>::type>{forward<F>(f)};
}
/****************************************************************/
// Proof-of-Concept
template<typename Base, typename ...Ts>
struct SubVariant
{
Base shared_data;
boost::variant<Ts...> sub;
template<typename Visitor>
friend auto apply(Visitor visitor, SubVariant &operand)
{
using result_type = typename common_type
<
decltype( visitor(shared_data, declval<Ts&>()) )...
>::type;
return boost::apply_visitor(make_result_type<result_type>([&](auto &x)
{
return visitor(operand.shared_data, x);
}), operand.sub);
}
};
/****************************************************************/
// Demo:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
use return new(p) static_cast<TO_T&&>(*p);
Here is a good resource regarding move semantics: What are move semantics?
You simply can't legally "change" the class of an object in C++.
However if you mention why you need this, we might be able to suggest alternatives. I can think of these:
Do v-tables "manually". In other words, each object of a given class should have a pointer to a table of function pointers that describes the behavior of the class. To modify the behavior of this class of objects, you modify the function pointers. Pretty painful, but that's the whole point of v-tables: to abstract this away from you.
Use discriminated unions (variant, etc.) to nest objects of potentially different types inside the same kind of object. I'm not sure if this is the right approach for you though.
Do something implementation-specific. You can probably find the v-table formats online for whatever implementation you're using, but you're stepping into the realm of undefined behavior here so you're playing with fire. And it most likely won't work on another compiler.
You should be able to reuse data by separating it from your Thing class. Something like this:
template <class TData, class TBehaviourBase>
class StateStorageable {
struct StateStorage {
typedef typename std::aligned_storage<sizeof(TData), alignof(TData)>::type DataStorage;
DataStorage data_storage;
typedef typename std::aligned_storage<sizeof(TBehaviourBase), alignof(TBehaviourBase)>::type BehaviourStorage;
BehaviourStorage behaviour_storage;
static constexpr TData *data(TBehaviourBase * behaviour) {
return reinterpret_cast<TData *>(
reinterpret_cast<char *>(behaviour) -
(offsetof(StateStorage, behaviour_storage) -
offsetof(StateStorage, data_storage)));
}
};
public:
template <class ...Args>
static TBehaviourBase * create(Args&&... args) {
auto storage = ::new StateStorage;
::new(&storage->data_storage) TData(std::forward<Args>(args)...);
return ::new(&storage->behaviour_storage) TBehaviourBase;
}
static void destroy(TBehaviourBase * behaviour) {
auto storage = reinterpret_cast<StateStorage *>(
reinterpret_cast<char *>(behaviour) -
offsetof(StateStorage, behaviour_storage));
::delete storage;
}
protected:
StateStorageable() = default;
inline TData *data() {
return StateStorage::data(static_cast<TBehaviourBase *>(this));
}
};
struct Data {
int a;
};
class Thing : public StateStorageable<Data, Thing> {
public:
virtual const char * type_name(){ return "Thing"; }
virtual int value() { return data()->a; }
};
Data is guaranteed to be leaved intact when you change Thing to other type and offsets should be calculated at compile-time so performance shouldn't be affected.
With a propert set of static_assert's you should be able to ensure that all offsets are correct and there is enough storage for holding your types. Now you only need to change the way you create and destroy your Things.
int main() {
Thing * thing = Thing::create(Data{42});
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
turn_thing_to<OtherThing>(thing);
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
Thing::destroy(thing);
return 0;
}
There is still UB because of not reassigning thing which can be fixed by using result of turn_thing_to
int main() {
...
thing = turn_thing_to<OtherThing>(thing);
...
}
Here is one more solution
While it slightly less optimal (uses intermediate storage and CPU cycles to invoke moving ctors) it does not change semantic of original task.
#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
A(A&& a) : x(std::move(a.x)), y(std::move(a.y)) {}
virtual const char* who() const { return "A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return "B"; }
B(A&& a) : A(std::move(a)) {}
};
template<class TO_T>
inline TO_T* turn_A_to(A* a) {
A temp(std::move(*a));
a->~A();
return new(a) B(std::move(temp));
}
int main()
{
A* pa = new A(123, "text");
pa->show(); // 0xbfbefa58 A 123 [text]
turn_A_to<B>(pa);
pa->show(); // 0xbfbefa58 B 123 [text]
}
and its ideone.
The solution is derived from idea expressed by Nickolay Merkin below.
But he suspect UB somewhere in turn_A_to<>().
I have the same problem, and while I'm not using it, one solution I thought of is to have a single class and make the methods switches based on a "item type" number in the class. Changing type is as easy as changing the type number.
class OneClass {
int iType;
const char* Wears() {
switch ( iType ) {
case ClarkKent:
return "glasses";
case Superman:
return "cape";
}
}
}
:
:
OneClass person;
person.iType = ClarkKent;
printf( "now wearing %s\n", person.Wears() );
person.iType = Superman;
printf( "now wearing %s\n", person.Wears() );

C++11 Dynamic Cast If Else Chain -> Switch

Consider the following:
struct B { };
template<typename T>
struct D : B
{
T t;
}
void g(int i) { ... }
void g(string s) { ... }
void g(char c) { ... }
void f(B* b)
{
if (dynamic_cast<D<int>*>(b))
{
g(dynamic_cast<D<int>*>(b)->t);
}
else if (dynamic_cast<D<string>*>(b))
{
g(dynamic_cast<D<string>*>(b)->t);
}
else if (dynamic_cast<D<char>*>(b))
{
g(dynamic_cast<D<char>*>(c)->t)
}
else
throw error;
};
Here there are only three possible types of T - int, string, char - but if the list of possible types were longer, say n, the if else chain would take O(n) to execute.
One way to deal with this would be to store an extra type code in D somehow and then switch on the type code.
The RTTI system must already have such a code. Is there someway to get access to it and switch on it?
Or is there a better way to do what I'm trying to do?
C++11 is almost there.
In C++03 it was impossible because the only way to get a compile-time constant (which case requires) was through the type system. Since typeid always returns the same type, it couldn't produce different alternatives for switch.
C++11 adds constexpr and type_info::hash_code as a unique identifier of types, but doesn't combine them. You can use typeid in a constant expression on a of type name or statically-typed expressions, but because hash_code is a non- constexpr function you cannot call it.
Of course there are various workarounds, one of which you describe, and the most general of which apply a visitor over a type vector using template metaprogramming.
Since only a few types are valid, you could solve this with virtual functions and template specialization instead:
struct B
{
virtual void g() = 0;
}
template<typename T>
struct D : public B
{
T t;
};
template<>
struct D<int> : public B
{
int t;
void g() { /* do something here */ }
};
template<>
struct D<std::string> : public B
{
std::string t;
void g() { /* do something here */ }
};
template<>
struct D<char> : public B
{
char t;
void g() { /* do something here */ }
};
void f(B* b)
{
b->g();
}
This will fail at compile-time if you provide the wrong types, instead or requiring runtime checks (which C++ is quite bad at).
The primary choice for run time switching on type in C++, is a virtual function.
It is dead simple:
#include <string>
#include <iostream>
using namespace std;
struct Base
{
virtual void g() const = 0;
};
template< class Type > void g( Type const& );
template<> void g( int const& ) { cout << "int" << endl; }
template<> void g( string const& ) { cout << "string" << endl; }
template<> void g( char const& ) { cout << "char" << endl; }
template< class Type >
struct Derived: Base
{
Type t;
virtual void g() const override { ::g<Type>( t ); }
};
void f( Base& b ) { b.g(); }
int main()
{
Derived<int>().g();
}
As you can it is also efficient, O(1) instead of the silly O(n). Plus, with static (compile time) type checking instead of dynamic (run time) type checking, saving a pretty annoying amount of testing. What more can I say? Really, forget about type code and enums and such. Remember that Bertrand Meyer chose to not support enums in Eiffel, for just this reason, that people tend to abuse them for type codes. Do use virtual functions.
Hey, virtual functions!
They're really useful when otherwise you'd want dynamic dispatch on type.
So, I recommend using virtual functions for that. :)
EDIT: templatized ::g in order to avoid possible ambiguities in the real code.