1

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.

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • If the object is actually a `Child` then there's no need to cast, it will use the proper version of the method because it's virtual. Using `Child`'s `foo` method on a `Parent` object wouldn't make sense, what if `foo` uses a member variable that doesn't exist in `Parent`? – Mark Ransom Jul 14 '15 at 03:14
  • @MarkRansom Wait I must be misunderstanding. Calling `foo.func()` will call `Parent::func()`. `Child::func()` does *not* use any members and it only changes the behavior of `func`, that's the reason that it seems like I should be able to cast, but I segfault when I try to cast, so it's obviously not legal. – Jonathan Mee Jul 14 '15 at 10:31
  • Where is your `Parent foo` stored? In a variable of type `Parent`? Then it is just a `Parent` (it probably was copy constructed from a `Child`, but then the copy is a `Parent`, not a `Child`) - If this is the case, you want it to be a reference or pointer type *before* you assign it from a `Child`. – leemes Jul 14 '15 at 10:44
  • @leemes I've clarified the question and added a link to an implementation of the problem that you can play around with. Assigning a `Parent*` to a `Child*` variable results in a segfault. – Jonathan Mee Jul 14 '15 at 11:40

4 Answers4

2

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:

  1. Friendships are not inherited, so you must then list all children to ParentHelper that you intend to use.
  2. It does, however, give you a way to access all the data members of your Parent class as is, it won't cause some weird behaviour.
  3. This may still not be what you are looking for, but from your question i think that it may help.
v010dya
  • 5,296
  • 7
  • 28
  • 48
  • Wow, that does actually work? Here's the question though, I have a `Child*`, why *wouldn't* polymorphisim insist that `Child::func` be called? Why would I need to call it explicitly? (Also the `friend` thing isn't really helpful. I'm inheriting from a standard implementation object, I have no way of modifying `Parent` code.) – Jonathan Mee Jul 14 '15 at 10:42
  • @JonathanMee Because you have a virtual function. Take a look at https://en.wikipedia.org/wiki/Virtual_method_table hopefully this will help. If it doesn't search for vtable. As for not being able to modify it, and yet trying to chage the way it operates, i think that you are doing something, which you shouldn't be; so be very careful, and perhaps rethink your design. – v010dya Jul 14 '15 at 11:01
  • If only I could :( `moneypunct` isn't mine it's standard implementation. I've edited the question to provide clearer explanation, basically I want a `moneypunct` object that calls the functions in my `punct_facet`. – Jonathan Mee Jul 14 '15 at 11:44
  • I'm accepting this, because it is a clean and cross-platform answer to the generalized question. But it s worth noting that this does not provide a solution to the specific question of how to convert a `moneypunct` into a `punct_facet`. That specific question is answered in a hacky and compiler-specific answer here: http://stackoverflow.com/a/31454039/2642059 – Jonathan Mee Jul 17 '15 at 10:52
1

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:

  1. is_standard_layout fails for your child because it has: "has virtual functions or virtual base classes"
  2. Your parent does not have an copy constructor or an assignment operator (otherwise you could just copy in the parent on construction of the child object)
  3. Your compiler does in fact implement a v-table
  4. Whether your v-table is at the beginning or end of the object layout
  5. The position your compiler assigns to child member variables relative to parent member variables in the object layout

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?"

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
0

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.

John3136
  • 28,809
  • 4
  • 51
  • 69
  • You know [`moneypunct`](http://en.cppreference.com/w/cpp/locale/moneypunct) is part of the standard right? I'm just trying to figure out how to use it effectively. – Jonathan Mee Jul 15 '15 at 11:05
0

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

Tim_King
  • 135
  • 8
  • 1
    Then why does `dynamic_cast` explicitly allow it? – RamblingMad Jul 14 '15 at 06:16
  • "legal" might not be accurate word here and yes you can do this explicitly by dynamic_cast, or by force conversion like pDerive = (Derive*)&BaseObj. What I mean here is that I think nothing meaningful could be achieved by assigning address of base object to pointer of derived class and usually it cause error or something you don't expect. dynamic_cast would return 0 in case you are doing pointer conversion, and throw exception if you are doing reference conversion. " pDerive = (Derive*)&BaseObj", virtual call by pDerive would call the virtual function in BaseObj instead of DeriveObj – Tim_King Jul 15 '15 at 04:04
  • Sometimes a child class will have data members you want to access, but that could be a sign of bad design – RamblingMad Jul 15 '15 at 04:07
  • More needs to be considered if Derive has more than 1 Base and/or virtual Base – Tim_King Jul 15 '15 at 04:13
  • @CoffeeandCode `dynamic_cast` allows what? – curiousguy Aug 02 '15 at 22:50
  • "_virtual call by pDerive would call the virtual function in BaseObj instead of DeriveObj_" or not; it could crash if the vtable is not compatible (if the base is not a primary base). You can't tell, it's undefined. – curiousguy Aug 02 '15 at 22:51