Reputation: 38919
What I'm actually trying to do is cast a constructed moneypunct
to the punct_facet
in this question without writing a copy constructor as in this answer.
But in the interests of writing a Minimal, Complete, Verifiable Example let's say that I have these two classes:
class Parent{
public:
Parent(Complex& args);
Parent operator=(const Parent&) = delete;
Parent(const Parent&) = delete;
Parent() = default;
virtual void func();
private:
Complex members;
};
class Child : public Parent{
public:
virtual void func();
};
I can construct a Parent
or Child
with the default constructor but that won't setup Complex members
. So say that I am given Parent foo
which was constructed using the custom constructor and I want to use the foo
object just with Child
's func
method. How do I do that? The straight up dynamic_cast<Child*>(&foo)
segfaults, so there may not be a way: http://ideone.com/JcAaxd
auto bar = dynamic_cast<Child*>(&foo);
Do I have to make a Child
constructor that takes a Parent
and internally copies it? Or is there some way to cast bar
into existence?
EDIT:
To give insight into my actual problem, the Parent
from the example is moneypunct
, which is implemented in the standard so I cannot modify it.
class punct_facet
is mine and the Child
from the example, it inherits moneypunct
and if I'm trying to stay implementation independent I cannot even internally use moneypunct
's member variables.
Which means that I must data mirror all of moneypunct
member variables in punct_facet
and copy construct them on punct_facet
construction. This results in an object that's twice as fat as it needs to be and requires me to reimplment all moneypunct
functionality.
Clearly that's undesirable, but the only way I can find around it is to take a previously constructed moneypunct
and treat it as a punct_facet
as requested by this question.
Upvotes: 1
Views: 708
Reputation: 38919
So this is implementation specific as Wikipedia notes:
The C++ standards do not mandate exactly how dynamic dispatch must be implemented, but compilers generally use minor variations on the same basic model.
Typically, the compiler creates a separate vtable for each class. When an object is created, a pointer to this vtable, called the virtual table pointer, vpointer or VPTR, is added as a hidden member of this object. The compiler also generates "hidden" code in the constructor of each class to initialize the vpointers of its objects to the address of the corresponding vtable.
Even worse Danny Kalev states:
Compilers can be divided into two categories with respect to their vptr's position. UNIX compilers typically place the vptr after the last user-declared data member, whereas Windows compilers place it as the first data member of the object, before any user-declared data members.
I give all the preceding information to indicate the conditions in which my hack will work:
is_standard_layout
fails for your child because it has: "has virtual functions or virtual base classes"With understanding of the hack that you are getting into I will now proceed to extend the classes in the question to better demonstrate how we can "Cast to a Child":
class Parent{
public:
Parent operator=(const Parent&) = delete;
Parent(const Parent&) = delete;
Parent() = default;
Parent(int complex) : test(complex) {}
virtual void func(){ cout << test; }
private:
int test = 0;
};
class Child : public Parent{
public:
Child operator=(const Child&) = delete;
Child(const Child&) = delete;
Child() = default;
Child(const Parent* parent){
const auto vTablePtrSize = sizeof(void*);
memcpy(reinterpret_cast<char*>(this) + vTablePtrSize,
reinterpret_cast<const char*>(parent) + vTablePtrSize,
sizeof(Parent) - vTablePtrSize);
}
virtual void func(){ cout << "Child, parent says: "; Parent::func(); }
};
We are simply using memcpy
to copying the state of the parent object, while allowing all Child
information to persist.
You can see that this code:
Parent foo(13);
Child bar(&foo);
bar.func();
Will print:
Child, parent says: 13
Live example and though it's not asked for in the question here's how it could be accomplished for multiple inheritance: http://ideone.com/1QOrMz
This is a useful solution for moneypunct
as it's initialization will be implementation specific anyway, since C++ does not specify any locale names other than:
""
"C"
"POSIX"
I would like to close this answer by pointing out that this entire post has been about how to overcome limitations intentionally put in place by the designers of moneypunct
. So, yes you can do this but as you do the obvious question should be asked: "Why were the copy constructor and assignment operator of moneypunct
deleted in the first place? What aspect of that design am I intentionally subverting?"
Upvotes: 1
Reputation: 135
It is not legal to assign address of base object to pointer of derived class.
If you want to call virtual function in derived class, you have to instantiate an object of derived class and call it thru this object, or pointer (of which type might be base class) to this object.
Virtual function tables in base and derived class are separated, so you cannot access virtual function of derived class thru an object of base class
Upvotes: 0
Reputation: 5848
It wouldn't work as you think, since you have made the function func
virtual. This means that even if you were to convert the pointer to Parent
to a pointer to Child
, the func()
of that object would still be Parent::func()
.
Now, you could theoretically do something like this:
#include <iostream>
class Parent
{
public:
virtual void foo() { std::cout << "parent" << std::endl; }
};
class Child : public Parent
{
public:
virtual void foo() { std::cout << "child" << std::endl; }
};
int main()
{
Child child;
child.foo(); // "child"
child.Parent::foo(); // "parent"
Parent parent;
parent.foo(); // "parent"
((Child*)(&parent))->foo(); // still "parent"
((Child*)(&parent))->Child::foo(); // "child"
return 0;
}
And while i may receive some downvotes for posting this broken code, i think that it is necessary to show what is happening in this case. You would need to convert both, the pointer to the object, and then specify exactly which function you are intending to call.
Depending upon what you are doing, it may better be accomplished by using friend classes:
#include <iostream>
class ParentHelper;
class ChildHelper;
class Parent
{
friend class ParentHelper;
friend class ChildHelper;
private:
int a=5;
};
class ParentHelper
{
public:
virtual void func(Parent *p)
{
std::cout << "parent helper, but i see a " << p->a << std::endl;
}
};
class ChildHelper : public ParentHelper
{
public:
virtual void func(Parent *p)
{
std::cout << "child helper, but i see a also " << p->a << std::endl;
}
};
void foo(Parent* p, ParentHelper *h)
{
h->func(p);
}
int main()
{
Parent p;
ParentHelper ph;
ChildHelper ch;
ph.func(&p);
ch.func(&p);
foo(&p, &ph);
foo(&p, &ch);
return 0;
}
Note several things:
Upvotes: 2
Reputation: 29266
If the parent ISA Child then the Child.func() will be called anyway.
If the parent is not a Child and you want the Child.func to be called then your design is broken.
Upvotes: 0