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

Virtual constructor & covariant return types

P: n/a
Here is a code from
http://www.parashift.com/c++-faq-lit....html#faq-20.8

--------------------------------------
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
virtual void draw() = 0; // A pure virtual function
virtual void move() = 0;
...
virtual Shape* clone() const = 0; // Uses the copy constructor
virtual Shape* create() const = 0; // Uses the default constructor
};

class Circle : public Shape {
public:
Circle* clone() const; // Covariant Return Types; see below
Circle* create() const; // Covariant Return Types; see below
...
};

Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}

--------------------------------------


It seems that behavior of the program will be the same one if we don't
use covariant return types, for instance

class Circle : public Shape {
public:
Shape* clone() const; // Non-Covariant Return Types
Shape* create() const; // Non-Covariant Return Types
...
};

Why do we need covariant return types in the "virtual constructor"
design pattern?

--
Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Jul 5 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a
* Alex Vinokur:
>
Why do we need covariant return types in the "virtual constructor"
design pattern?
You don't absolutely /need/ them: they're a convenience feature to avoid
casts.

First, where might you actually use a covariant result? When you
statically know the type (or at least, a more specialized type than
Base) of the object you're cloning or using as an examplar. In that
case, you're avoiding a downcast in the client code.

That downcast in the client code can be avoided anyway, but at the cost
of a centralized downcast in the class' code, or the cost of not
supporting derived classes. The covariance feature removes that cost,
but only for built-in pointers and references. For smart-pointers you
have to cope with it and choose your poison.

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

P: n/a

"Alf P. Steinbach" <al***@start.nowrote in message news:4h*************@individual.net...
* Alex Vinokur:

Why do we need covariant return types in the "virtual constructor"
design pattern?

You don't absolutely /need/ them: they're a convenience feature to avoid
casts.
[snip]

--- Covariant Return Types ---
class Circle : public Shape {
public:
Circle* clone() const;
Circle* create() const;
...
};

--- Non-Covariant Return Types ---
// Use of this class requires no casts.
class Circle : public Shape {
public:
Shape* clone() const;
Shape* create() const;
...
};
--
Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Jul 5 '06 #3

P: n/a
Alex Vinokur wrote:
"Alf P. Steinbach" <al***@start.nowrote in message news:4h*************@individual.net...
>* Alex Vinokur:
>>Why do we need covariant return types in the "virtual constructor"
design pattern?
You don't absolutely /need/ them: they're a convenience feature to avoid
casts.
[snip]

--- Covariant Return Types ---
class Circle : public Shape {
public:
Circle* clone() const;
Circle* create() const;
...
};

--- Non-Covariant Return Types ---
// Use of this class requires no casts.
class Circle : public Shape {
public:
Shape* clone() const;
Shape* create() const;
...
};
Your second class does in fact require casts.

Circle aCircle;
Circle* badClone = aCircle.clone(); // ERROR!!!!
Circle* goodClone = static_cast<Circle*>(aCircle.clone);

Note that dynamic_cast would also be acceptable (assuming a virtual
function somewhere).

The first class requires no such casts, and since upcasts to the base
class (Shape) do not require a cast either, that method is preferable.
Jul 5 '06 #4

P: n/a

"red floyd" <no*****@here.dudewrote in message news:vC*********************@newssvr21.news.prodig y.com...
Alex Vinokur wrote:
"Alf P. Steinbach" <al***@start.nowrote in message news:4h*************@individual.net...
* Alex Vinokur:
Why do we need covariant return types in the "virtual constructor"
design pattern?
You don't absolutely /need/ them: they're a convenience feature to avoid
casts.
[snip]

--- Covariant Return Types ---
class Circle : public Shape {
public:
Circle* clone() const;
Circle* create() const;
...
};

--- Non-Covariant Return Types ---
// Use of this class requires no casts.
class Circle : public Shape {
public:
Shape* clone() const;
Shape* create() const;
...
};

Your second class does in fact require casts.

Circle aCircle;
Circle* badClone = aCircle.clone(); // ERROR!!!!
Circle* goodClone = static_cast<Circle*>(aCircle.clone);
[snip]

OK.
But my second class requires no casts for sample in http://www.parashift.com/c++-faq-lit....html#faq-20.8

--
Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Jul 5 '06 #5

P: n/a
red floyd wrote:
Alex Vinokur wrote:
>"Alf P. Steinbach" <al***@start.nowrote in message
news:4h*************@individual.net...
>>* Alex Vinokur:
Why do we need covariant return types in the "virtual constructor"
design pattern?
You don't absolutely /need/ them: they're a convenience feature to
avoid casts.
[snip]

--- Covariant Return Types ---
class Circle : public Shape {
public:
Circle* clone() const;
Circle* create() const;
...
};

--- Non-Covariant Return Types ---
// Use of this class requires no casts.
class Circle : public Shape {
public:
Shape* clone() const;
Shape* create() const;
...
};

Your second class does in fact require casts.

Circle aCircle;
Circle* badClone = aCircle.clone(); // ERROR!!!!
Circle* goodClone = static_cast<Circle*>(aCircle.clone);
Nit pick:

Circle* goodClone = static_cast<Circle*>(aCircle.clone());

(you'd forgotten parentheses after 'clone')
Note that dynamic_cast would also be acceptable (assuming a virtual
function somewhere).
Why assuming? Why somewhere? Covariant return types _require_ the
function to be virtual, don't they?
The first class requires no such casts, and since upcasts to the base
class (Shape) do not require a cast either, that method is preferable.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 5 '06 #6

P: n/a
Alex Vinokur <al****@users.sourceforge.netwrote:
"red floyd" <no*****@here.dudewrote in message
news:vC*********************@newssvr21.news.prodig y.com...
>Alex Vinokur wrote:
>>"Alf P. Steinbach" <al***@start.nowrote in message
news:4h*************@individual.net...
>>>* Alex Vinokur:
>>>>Why do we need covariant return types in the "virtual constructor"
design pattern?
>>>You don't absolutely /need/ them: they're a convenience feature to
avoid casts.
>>[snip]

--- Covariant Return Types ---
class Circle : public Shape {
public:
Circle* clone() const;
Circle* create() const;
...
};

--- Non-Covariant Return Types ---
// Use of this class requires no casts.
class Circle : public Shape {
public:
Shape* clone() const;
Shape* create() const;
...
};
>Your second class does in fact require casts.

Circle aCircle;
Circle* badClone = aCircle.clone(); // ERROR!!!!
Circle* goodClone = static_cast<Circle*>(aCircle.clone);
OK.
But my second class requires no casts for sample in
http://www.parashift.com/c++-faq-lit....html#faq-20.8
The sample should have made use of the feature provided by covariant
return types. But it did not, that is why you do not need a cast. Change
the userCode function to:

void userCode(Circle& c)
{
Circle* s2 = c.clone();
Circle* s3 = c.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}

And you will need a cast somewhere unless you use covariant return
types.

regards
--
jb

(reply address in rot13, unscramble first)
Jul 5 '06 #7

P: n/a

"Jakob Bieling" <ar****************@rot13.comwrote in message news:e8**********@f1node01.rhrz.uni-bonn.de...
Alex Vinokur <al****@users.sourceforge.netwrote:
[snip]
But my second class requires no casts for sample in
http://www.parashift.com/c++-faq-lit....html#faq-20.8

The sample should have made use of the feature provided by covariant
return types. But it did not, that is why you do not need a cast. Change
the userCode function to:

void userCode(Circle& c)
{
Circle* s2 = c.clone();
Circle* s3 = c.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}
[snip]

I think, if we use userCode(Circle&) instead of userCode(Shape&) it is not a virtual constructor.

--
Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Jul 6 '06 #8

P: n/a
Alex Vinokur <al****@users.sourceforge.netwrote:
"Jakob Bieling" <ar****************@rot13.comwrote in message
news:e8**********@f1node01.rhrz.uni-bonn.de...
>Alex Vinokur <al****@users.sourceforge.netwrote:
[snip]
>>But my second class requires no casts for sample in
http://www.parashift.com/c++-faq-lit....html#faq-20.8

The sample should have made use of the feature provided by
covariant return types. But it did not, that is why you do not need
a cast. Change the userCode function to:

void userCode(Circle& c)
{
Circle* s2 = c.clone();
Circle* s3 = c.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}
[snip]

I think, if we use userCode(Circle&) instead of userCode(Shape&)
it is not a virtual constructor.
Right, but it makes use of covariant return types. Obviously, you
have to know the returned type at compile-time, so the virtual
construction mechanism is not used. You use one *or* the other. But
covariant return types make it possible to use both (in different
places) with the same code without the need for a cast.

--
jb

(reply address in rot13, unscramble first)
Jul 6 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.