views:

337

answers:

7

Update 1:

Corrected nonsense code! Thanks for comments, I made a hash of the first snippet, oops.

Update 2:

Also updated question title, as the use of dynamic_cast has been pointed out as not necessary by answers.

What I'm trying to achieve here is a deep copy using strong types; I want to be able to copy Class2 to another instance of Class2; however, I also want to use the CopyTo function from the Class1 which is the base. This idea comes from my C# experience, where usually I'd just make the return type generic (see C# snippet).

void Class1::CopyTo(Class1 *c1)
{
    // Write data in to c1 from this instance.
    c1->exampleData = exampleData;
}

// Class2 inherits Class1
Class2 *Class2::Copy()
{
    Class2 *c2a = new Class2();
    CopyTo(c2a);

    Class2 *c2b = dynamic_cast<Class2*>(c2a);
    return c2a;
}

And here's the way I'd so it in C#:

public class Class1
{
    T Copy<T>()
        where T : Class1
    {
        /* Can't remember the best way to do this in C#;
         * basically if T was Class2 this would need to create
         * a new instance of that class, and the same goes for
         * Class1. */         
        T copy = createNewInstance();

        // Copy the data from this to 'copy'.
        copy.exampleData = exampleData;

        return copy;
    }
}

Now, compared to the C# snippet, the C++ snippet feel smelly. Is it possible to do this without pointers, or is this way best practice?

A: 

that code makes no sense as stated... anyways I "guess" you could use static cast if you didn't use a void* as return ?

Ok now the code makes sense.

You don't need any dynamic cast, its already of type Class2.

Robert Gould
Sorry, updated now. It's pseudo code I quickly threw together.
nbolton
+1  A: 

I'm not clear what you are asking, but be aware that when you say:

 Class2 *c2 = dynamic_cast<Class2*>(c1);

the result of the cast could be NULL and you must check for this.

anon
Updated snippet.
nbolton
A: 

In your CopyTo function, you would be returning a pointer to an object that was created on the stack - this is an impossibility because the object the pointer points at will be destroyed when the function returns.

In answer to your question, you can use dynamic_cast on a pointer or a reference. In your case, I might allocate the object to be returned dynamically using new rather than on the stack, then you could safely return a pointer. However I tend to look on using dynamic_cast as a potential code smell, and a sign that a virtual function should be being used.

1800 INFORMATION
Yeah, it feels extremely smelly. I'm used to generic types in C#, and I'm just trying to find the C++ equivalent.
nbolton
The generic type equivalent in C++ is templates. They even have a similar angle bracket notation, and no safety bars (mucho powerful, awfully complex at times). Or what do you mean by 'generic type', exactly?
Pontus Gagge
What makes you say that templates have no safety bars? They are checked at compile time. Unlike runtime artifacts (dynamic_cast among them) that depend on many other things, templates are verified at compile time. It is just hard to understand the compiler errors, but if it compiles it is safe.
David Rodríguez - dribeas
A: 

No, dynamic_cast only works with pointers and references. You couldn't return anything you allocate on the stack safely anyway, so I'm not sure how you were intending to modify your code in this case.

Dan Olson
+1  A: 

You should work on the code snippet a little more. GetSomethingCopy is creating a pointer of type Class2 that is being passed to CopyTo. CopyTo tries to call a member function of the received pointer that has never been initialized: segmentation fault and the program dies.

Even if that did not kill the application, you are trying to dynamic_cast from Class2* to Class2* which is just about doing nothing. If what you intend is casting the returned value from CopyTo, you must know that you cannot use dynamic_cast on void*. You must either change CopyTo signature to return Class1 (so that you can later cast it) or use static_cast on the void*.

Note that either Copy is a virtual function in Class1 that is in fact executed in Class2 and does create a Class2 object, or else, the returned element will not be a Class2, but rather a Class1.

The name of the method CopyTo is confusing as it is not copying to the argument but rather from the argument.

And after all this, I still not know what you are asking about. Where would you want to use stack memory? You can pass an stack allocated element to a function, but returning a pointer/reference to an stack allocated element is again a segmentation fault: the object will be destroyed when the function ends and the receiver will be left with a dangling pointer/reference.

Now, if your question is more theoretical on whether you can use dynamic_cast on a stack allocated element, you can (provided that Class2 inherits from Class1):

void f()
{
   Class2 c2;
   Class1 &c1 = c2; // c1 is a Class1 reference to a Class2 object

   dynamic_cast<Class2&>(c1).class2method(); 
   // or:
   dynamic_cast<Class2*>(&c1)->class2method();
}

If you update the code, post a comment in this answer so that I notice and can correct it tonight.

David Rodríguez - dribeas
Yep, you're exactly right, my mistake. I should really have run that through a compiler. Should make sense now...
nbolton
You corrected the problem with the CopyTo parameter being uninitialized, but the rest of the problems are still there.
David Rodríguez - dribeas
A: 

I'm not sure what you are trying to achieve because the code still doesn't make much sense. However, I believe the following should approximate what you're trying to do. Note that I don't use heap memory: it's not necessary and it would leak memory.

template <typename T>
T Class1::Copy()
{
    T instance;
    CopyTo(&instance);
    return instance;
}

This works because you pass a (polymorphic) pointer to instance to the CopyTo method of Class1.

Then you could call the code like this:

Class2 x1;
// Fill x1
Class2 x2 = x1.Copy<Class2>();

However, this code still smells because it's no idiomatic C++: In C++, you would usually write a copy constructor instead. Late-bound Copy methods do exist but they are very rarely needed, and the above is not late bound (but neither is your C# code).

Konrad Rudolph
Ah, so I would be better off copying from the constructor? That would make more sense... Right?
nbolton
The point is that in C++, the simple operation `x = y` makes a copy, unlike C# because all variables have value semantics. So, implementing the copy constructor and assignment operator is the better solution.
Konrad Rudolph
I am not too sure of this solution. To me the question implies a virtual clone method that is lost in this solution. If it is like that, you cannot avoid pointers.
David Rodríguez - dribeas
@dribeas: Well the C# code isn't a virtual clone method either, and it wouldn't work that way. As it is, the code is strictly statical. All it does is to avoid some code duplication through inheritance (which is probably good).
Konrad Rudolph
A: 

Ah, now the problem is clear. The answer is technically no, not withh dynamic_cast<>, but I'm really failing to see why you'd want it anyway. It seems you just want

void Class1::CopyTo(Class1& c1)
{
    // Write data in to c1 from this instance.
    c1.SomeIntValue = SomeIntValue;
}

// Class2 inherits Class1
Class2* Class2::Copy()
{
    Class2 *c2 = new Class2();
    CopyTo(*c2);
    return c2;
}
//or more idiomatic
Class2 Class2::Copy()
{
    Class2 c2
    CopyTo(c2);
    return c2;
}
MSalters