views:

415

answers:

6

Consider:

class A
{
public:
    A( int val ) : m_ValA( val ) {}
    A( const A& rhs ) {}
    int m_ValA;
};

class B : public A
{
public:
    B( int val4A, int val4B ) : A( val4A ), m_ValB( val4B ) {}
    B( const B& rhs ) : A( rhs ), m_ValB( rhs.m_ValB ) {}
    int m_ValB;
};

int main()
{
    A* b1 = new B( 1, 2 );
    A* b2 = new A( *b1 ); // ERROR...but what if it could work?
    return 0;
}

Would C++ be broken if "new A( b1 )" was able to resolve to creating a new B copy and returning an A?

Would this even be useful?

+10  A: 

Do you need this functionality, or is this just a thought experiment?

If you need to do this, the common idiom is to have a Clone method:

class A
{
public:
    A( int val ) : m_ValA( val ) {}
    A( const A& rhs ) {}
    virtual A *Clone () = 0;
    int m_ValA;
};

class B : public A
{
public:
    B( int val4A, int val4B ) : A( val4A ), m_ValB( val4B ) {}
    B( const B& rhs ) : A( rhs ), m_ValB( rhs.m_ValB ) {}
    A *Clone() { return new B(*this); }
    int m_ValB;
};

int main()
{
    A* b1 = new B( 1, 2 );
    A* b2 = b1->Clone();
    return 0;
}
eduffy
+1, but I would also add a virtual destructor to the class ;)
Faisal Vali
It was indeed a thought experiment. And while this is the standard way to implement virtual copy constructors, I was curious why the language doesn't provide a standardised way to do this.
0xC0DEFACE
A: 

Yes. No.

There are a number of ways of implementing cloning (e.g. the more or less standard clone() method, parameterized variations of object factories, with or without configurable dependency injection) without changing the meaning of existing programs, or making it impossible to create instances of base classes when a derived class is known within a compilation unit.

Constructors and destructors are sufficiently complex to understand for beginners as is. Injecting even more complexity into them would be unwise.

Pontus Gagge
+1  A: 

The expression

new A(*b1)

already has a meaning, supposing you had the appropriate overload.

If it was given a different meaning, you'd have to provide another way to get the other meaning. This is kind of pointless given that there is already a way to get the meaning you want:

new B(*b1)

And guess which is clearer to read.

Daniel Earwicker
+2  A: 

What you're really looking for is called a virtual copy constructor, and what eduffy posted is the standard way of doing it.

There are also clever ways of doing it with templates. (disclaimer: self-promotion)

Tyler McHenry
A: 

As pointed out above there are a number of ways of implementing this.

To answer your question if new A( *b1 ) returned an new instance of B then this would not work.

int main()
{
    A* b1 = new B( 1, 2 );
    A a( *b1 ); // What size would 'a' be if it was polymorphicly constructed?
    return 0;
}
iain
A: 

Just a small addition to the answer by eduffy: Instead of

class B : public A {
  ...
  A *Clone() { return new B(*this); } 
  ...

};

you can declare it like this:

class B : public A {
  ...
  B *Clone() { return new B(*this); } // note: returning B *
  ...

};

It's still considered a valid overriding of the virtual A::Clone(); and is better if called directly through B *

anatoli