By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,714 Members | 1,340 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,714 IT Pros & Developers. It's quick & easy.

Virtual Constructor and Covariant Return Types

P: n/a
Hello,

Here is some program with virtual constructors.

Is there any difference between
* clone1() vs. clone2()
* create1() vs. create2() ?

It seems that it should be.

The program has been successfully compiled and invocated.

------ C++ code : BEGIN ------
class Shape
{
public:
virtual ~Shape() {}

virtual void draw() = 0;

virtual Shape* clone1() const = 0;
virtual Shape* create1() const = 0;

virtual Shape* clone2() const = 0;
virtual Shape* create2() const = 0;

};

class Circle : public Shape
{
public:
void draw() {}

// --- Covariant Return Types ---
Circle* clone1() const { return new Circle(*this); }
Circle* create1() const { return new Circle();}
// ------------------------------

// --- NonCovariant Return Types ---
Shape* clone2() const { return new Circle(*this); }
Shape* create2() const { return new Circle();}
// ---------------------------------

};

void userCode(Shape& s)
{
Shape* sclone1 = s.clone1();
Shape* screate1 = s.create1();

Shape* sclone2 = s.clone2();
Shape* screate2 = s.create2();
sclone1->draw();
screate1->draw();

sclone2->draw();
screate2->draw();

delete sclone1;
delete screate1;

delete sclone2;
delete screate2;

}

int main()
{
Shape* s = new Circle;
userCode (*s);

delete s;

return 0;
}
------ C++ code : END --------

--
Alex Vinokur
mailto:al****@connect.to
http://mathforum.org/library/view/10978.html

Jul 22 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Alex Vinokur wrote:
Here is some program with virtual constructors.

Is there any difference between
* clone1() vs. clone2()
* create1() vs. create2() ?
[...]
// --- Covariant Return Types ---
Circle* clone1() const { return new Circle(*this); }
Circle* create1() const { return new Circle();}
// ------------------------------

// --- NonCovariant Return Types ---
Shape* clone2() const { return new Circle(*this); }
Shape* create2() const { return new Circle();}
// ---------------------------------


[...]

Sorry, am I missing the point? You can see the what the difference is.

--
Regards,
Buster.
Jul 22 '05 #2

P: n/a
* "Alex Vinokur" <al****@big.foot.com> schriebt:
Here is some program with virtual constructors.
Would be nice if people stopped using that term, even though it is
in the FAQ... ;-)
Is there any difference between
* clone1() vs. clone2()
* create1() vs. create2() ?

class Circle : public Shape
{
public:
void draw() {}

// --- Covariant Return Types ---
Circle* clone1() const { return new Circle(*this); }
Circle* create1() const { return new Circle();}
// ------------------------------

// --- NonCovariant Return Types ---
Shape* clone2() const { return new Circle(*this); }
Shape* create2() const { return new Circle();}
// ---------------------------------

};


The difference is not in what they do, but in the static type-checking
available for client code.

Btw. it's a good idea to indicate deallocation responsibility in some
way, e.g. by returning smart-pointers instead of raw pointers.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #3

P: n/a
Alex Vinokur wrote:

Hello,

Here is some program with virtual constructors.

Is there any difference between
* clone1() vs. clone2()
* create1() vs. create2() ?

It seems that it should be.


No. Semantically they are equivalent.
Covariant return types are just a compile time
only thing. The created object is of type Circle
and thus both functions return a Circle*. Even
if in one of them the Circle* is called Shape*
The thing with covariant return types is this:
sometimes you call the virtual function and you know
exactly what the returned pointer must be.
Example:

Circle A;

Circle* B = A.clone();

The thing returned from A.clone() must be Circle* since A is a Circle.
It can't be anything else. Yet you are forced (without covariant
return types) to use a cast:

Circle* B = dynamic_cast< Circle* >( A.clone() );

or to make B a different type:

Shape* B = Circle.clone();

because the return value in the clone() function in the base class,
specified Shape* as return value.

This is where covariant return types help: If you (and the
compiler) know exactly which one of the derived class pointer
is returned, you can use it directly without going though the hassle
of casting.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #4

P: n/a

"Buster" <no***@nowhere.com> wrote in message news:c5**********@newsg3.svr.pol.co.uk...
Alex Vinokur wrote:
Here is some program with virtual constructors.

Is there any difference between
* clone1() vs. clone2()
* create1() vs. create2() ?


[...]
// --- Covariant Return Types ---
Circle* clone1() const { return new Circle(*this); }
Circle* create1() const { return new Circle();}
// ------------------------------

// --- NonCovariant Return Types ---
Shape* clone2() const { return new Circle(*this); }
Shape* create2() const { return new Circle();}
// ---------------------------------


[...]

Sorry, am I missing the point? You can see the what the difference is.


clone1() and create1() return Circle*,
clone2() and create2() return Shape*.

The question is if we can use
* create2() instead of create1(),
* clone2() instead of clone1()
with the same results.

--
Alex Vinokur
mailto:al****@connect.to
http://mathforum.org/library/view/10978.html

Jul 22 '05 #5

P: n/a


Alex Vinokur wrote:
Sorry, am I missing the point? You can see the what the difference is.
clone1() and create1() return Circle*,
clone2() and create2() return Shape*.


Exactly that.
The question is if we can use
* create2() instead of create1(),
* clone2() instead of clone1()
with the same results.


Yes.

Circle c;
Circle * p = static_cast <Circle *> (c.create2 ());
Circle * q = static_cast <Circle *> (c.clone2 ());

You should probably declare the "create" functions static and the
constructors private or protected.

--
Regards,
Buster.
Jul 22 '05 #6

P: n/a


Karl Heinz Buchegger wrote:
Alex Vinokur wrote: The thing returned from A.clone() must be Circle* since A is a Circle.
It can't be anything else. Yet you are forced (without covariant
return types) to use a cast:

Circle* B = dynamic_cast< Circle* >( A.clone() );


static_cast is sufficient, since we already know the dynamic type.
dynamic_cast is for querying the type.

--
Regards,
Buster.
Jul 22 '05 #7

P: n/a
Buster wrote:

Karl Heinz Buchegger wrote:
Alex Vinokur wrote:

The thing returned from A.clone() must be Circle* since A is a Circle.
It can't be anything else. Yet you are forced (without covariant
return types) to use a cast:

Circle* B = dynamic_cast< Circle* >( A.clone() );


static_cast is sufficient, since we already know the dynamic type.
dynamic_cast is for querying the type.


Ah. yes.
--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.