C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

design question: deriving from a concrete class
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
deb@pixar.com
Guest





PostPosted: Mon Aug 15, 2005 6:29 pm    Post subject: design question: deriving from a concrete class Reply with quote



I've got a design issue that runs afoul of two issues:
(1) I've read many times that when writing a base class you
expect people to derive from, the class should be abstract.

(2) Lots of casting is bad.

Here's the story: I have a concrete base class TriangleMesh, which is
useful by itself. A TriangleMesh, among other things, owns/creates a
bunch of TriangleVertex objects. Because I expect the user might want
to extend the data in TriangleVertex, I make the TriangleMesh class
have a virtual "factory" function.

For example:

class TriangleVertex {
public:
virtual ~TriangleVertex();

// various accessors: e.g. position, etc.
TriangleVertex* GetClosestNeighbor();

...
};

class TriangleMesh {
public:
virtual ~TriangleMesh();

TriangleVertex* GetVertex(size_t index) {
return _vertices[index];
}

// imagine a whole bunch more accessors on TriangleVertex

private:
// default implementation:
virtual TriangleVertex* NewVertex() {
return new TriangleVertex;
}

vector<TriangleVertex*> _vertices;
};


OK, so now someone can derive off of both TriangleVertex, and
TriangleMesh, and in particular redefine NewVertex() to return their
derived TriangleVertex class:

class WeightedTriangleVertex : public TriangleVertex {
public:
double GetWeight();
void SetWeight(double);
private:
double _weight;
};

class WeightedTriangleMesh : public TriangleMesh {
private:
virtual TriangleVertex* NewVertex() {
return new WeightedTriangleVertex;
}

}:

So one thing is that when you're working in the derived classes, you
end up with a lot of casting going on, because you're constantly using
the accessors from the base mesh class, but you want back the derived
class to get to the extra state variables:

WeightedTriangleMesh* mesh = ...;
mesh->GetVertex(index)->SetWeight(...); // XX: needs a cast...

And, like I said, it bothers me slightly that TriangleMesh is useful on
its own, i.e. is concrete, because of the principle of trying to derive
from non-concrete classes.

Thoughts?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Marco Manfredini
Guest





PostPosted: Mon Aug 15, 2005 9:51 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote



[email]deb (AT) pixar (DOT) com[/email] wrote:

Quote:
I've got a design issue that runs afoul of two issues:
(1) I've read many times that when writing a base class you
expect people to derive from, the class should be abstract.

(2) Lots of casting is bad.


So one thing is that when you're working in the derived classes, you
end up with a lot of casting going on, because you're constantly using
the accessors from the base mesh class, but you want back the derived
class to get to the extra state variables:

WeightedTriangleMesh* mesh = ...;
mesh->GetVertex(index)->SetWeight(...); // XX: needs a cast...


Let the user reimplement GetVertex(size_t) in WeigthedTriangleMesh to
return a WeightedTriangleVertex.

WeightedTriangleVertex* WeigthedTriangleMesh::GetVertex(size_t index)
{
return (WeightedTriangleVertex*) this->TriangleMesh::GetVertex(index);
}


Quote:
And, like I said, it bothers me slightly that TriangleMesh is useful
on its own, i.e. is concrete, because of the principle of trying to
derive from non-concrete classes.

Thoughts?

What has the Mesh to know about the Vertex, except knowing how to create
new ones? Chance that Mesh<_VertexType_> could be a better idea?

Marco



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Victor Bazarov
Guest





PostPosted: Mon Aug 15, 2005 9:54 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote



[email]deb (AT) pixar (DOT) com[/email] wrote:
Quote:
I've got a design issue that runs afoul of two issues:
(1) I've read many times that when writing a base class you
expect people to derive from, the class should be abstract.

Where did you read that nonsense?

Quote:
(2) Lots of casting is bad.

That I agree with.

Quote:

[...]
And, like I said, it bothers me slightly that TriangleMesh is useful on
its own, i.e. is concrete, because of the principle of trying to derive
from non-concrete classes.

Thoughts?

Forget about not deriving from concrete classes and just do it.

V

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Tue Aug 16, 2005 11:05 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

It appears that you are trying to create virtual constructors. The
theory behind your use of virtual constructors. As the thread from
www.parasoft.com below shows you will have to use Visual C++ 7.0 to
achieve what you want:



[20.8] What is a "virtual constructor"?
An idiom that allows you to do something that C++ doesn't directly
support.

You can get the effect of a virtual constructor by a virtual clone()
member function (for copy constructing), or a virtual create() member
function (for the default constructor).


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(); }
In the clone() member function, the new Circle(*this) code calls
Circle's copy constructor to copy the state of this into the newly
created Circle object. (Note: unless Circle is known to be final (AKA a
leaf), you can reduce the chance of slicing by making its copy
constructor protected.) In the create() member function, the new
Circle() code calls Circle's default constructor.

Users use these as if they were "virtual constructors":


void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}
This function will work correctly regardless of whether the Shape is a
Circle, Square, or some other kind-of Shape that doesn't even exist
yet.

Note: The return type of Circle's clone() member function is
intentionally different from the return type of Shape's clone() member
function. This is called Covariant Return Types, a feature that was not
originally part of the language. If your compiler complains at the
declaration of Circle* clone() const within class Circle (e.g., saying
"The return type is different" or "The member function's type differs
from the base class virtual function by return type alone"), you have
an old compiler and you'll have to change the return type to Shape*.

Note: If you are using Microsoft Visual C++ 6.0, you need to change the
return types in the derived classes to Shape*. This is because MS VC++
6.0 does not support this feature of the language. Please do not write
me about this; the above code is correct with respect to the C++
Standard (see 10.3p5); the problem is with MS VC++ 6.0. Fortunately
covariant return types are properly supported by MS VC++ 7.0.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Wu Yongwei
Guest





PostPosted: Tue Aug 16, 2005 11:06 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

[email]deb (AT) pixar (DOT) com[/email] wrote:
Quote:
I've got a design issue that runs afoul of two issues:
(1) I've read many times that when writing a base class you
expect people to derive from, the class should be abstract.

The suggestion comes from the fact that one might mistakenly slice an
object. Consider:

class A { ... };
class B : public A { ... };
A* p = new B;
A* q = new B;
....
*p = *q;

However, I do not think it justified. The fact that C++ allows object
copy is not a hindrance to design. Requiring all non-leaf class to be
abstract is counter-intuitive and the opposite works quite well in C++
and other OO languages. The real suggestion should be `avoid object
copy (use pointer assignment instead) if polymorphism is used'.

Best regards,

Yongwei


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
deb@pixar.com
Guest





PostPosted: Tue Aug 16, 2005 11:24 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

Marco writes:
What has the Mesh to know about the Vertex, except knowing how to
create
new ones? Chance that Mesh<_VertexType_> could be a better idea?


Sorry, this is a very very truncated example. Mesh needs to know a
*lot* about vertices, to do also sorts of comparisons. Mesh has to
create vertices, wire them together, form edges, faces (two more
datastructures I left out for brevity). This is not an example where
templating would be appropriate.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
deb@pixar.com
Guest





PostPosted: Tue Aug 16, 2005 11:24 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Victor Bazarov
Guest





PostPosted: Tue Aug 16, 2005 2:37 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote

[email]deb (AT) pixar (DOT) com[/email] wrote:
Quote:
Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....

I think you misunderstood Item 33 or misstated your question. You should
only make your class abstract if it is not intended to be instantiated by
itself. Not if it is intended to be derived from. Those two concepts are
not the same.

I've written many classes that worked fine by themselves or if derived
from. They weren't abstract. Hey, std::basic_streambuf is not abstract
(is it?) and it _is_ intended to be derived from.

In his Item 32 (referred to in Item 33) Scott uses what I consider too
strong a tone. "Don't just recommend any particular use of your classes,
restrict the users". This is good in a kindergarten. In the real world,
you should rely on others not doing harm to themselves providing all kinds
of diagnostics instead of keeping them in a protective bubble.

Yes, it's possible to install all kinds of fences around the danger zone,
but that's not going to stop some folks to want to go there. Wouldn't it
be better to display a well-visible sign about the danger and let those
who do want to challenge themselves actually work around the difficulties
legally, without trying to break your code? As you can probably see, I am
all for safety wheels (that can be taken off) instead of reins and blinds.

V

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Frank Chang
Guest





PostPosted: Tue Aug 16, 2005 2:40 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote

Sorry about the typos in the last message. I meant to say that the
theory behind virtual constructors is well established. It is the
implementation of virtual constructors that varies from compiler to
compiler. The C++ standard/VC 7.0 compiler supports covariant return
types which you may want to incorporate in you design. For example ,
you can change the virtual constructor in :

class WeightedTriangleMesh : public TriangleMesh {
private:
virtual TriangleVertex* NewVertex() {
return new WeightedTriangleVertex;
}


to


class WeightedTriangleMesh : public TriangleMesh {
private:
virtual WeightedTriangleVertex* NewVertex() {
return new WeightedTriangleVertex;
}
}:

Finally, base classes do always not need to be abstract. However, in
the ARM , Margaret Ellis and Bjarne Stroustrup (page 214) write " The
abstract class mechanism supports the notion of a general concept, such
as a shape, of which only more concrete variants, such as circle and
square, can actually be used". So, you must ask yourself does your
class TriangleVertex support the notion of a general concept? Thank
you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Tue Aug 16, 2005 5:59 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote

Not sure if you noticed a crucial part of what Marco was trying to tell
you: a virtual function in a derived class can return a pointer to a
type derived from the function's return type in the base class. So,
your code changes as follows:

class WeightedTriangleMesh : public TriangleMesh {
private:
virtual WeightedTriangleVertex* NewVertex() { // <---- note new
return type
return new WeightedTriangleVertex;
}
}:

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Greg
Guest





PostPosted: Tue Aug 16, 2005 11:33 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote

[email]deb (AT) pixar (DOT) com[/email] wrote:
Quote:
Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....



Sutter's and Alexandrescu's "C++ Coding Standards" offers similar
advice: favoring abstract classes when inheriting. Regardless of its
endorsements, the advice itself is absolutely sound.

The difficulty presented when inheriting from a concrete class is
meeting the requirement of substitutability. The derived class must be
able to stand in for the base class everywhere the base class could be
used. When the base is an abstract class, this means that the derived
class must adhere to an interface, but when the base class is concrete
the derived class must adhere to both an interface and an
implementation. The derived class is often overly constrained in this
situation because its implementation must continue to meet the clients'
expectations that have been set by the base class's implementation. But
it is difficult often just to identify those expectations, much less
respect them while trying at the same time to differ from the base
class in some appreciable way

To return to the original post: I would advice not letting clients
subclass TriangleMesh just to overide one routine. Instead, place that
factory routine in a separate class and have it act as a "component"
that is passed to TriangeMesh's constructor. Clients could specify
their own components that would produce their own TriangeVertex
classes.

Alternately, make TriangleMesh a class template and clients can
specialize its behavior to suit their own custom triangle vertex types.


The solution to the casting problem (if you stick with inheritence) is
to use "covariant return types". Have the derived class override the
accessor method in the base class and declare the routine in the
derived class to return a type that is derived from the type returned
by the base class method.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Wu Yongwei
Guest





PostPosted: Wed Aug 17, 2005 8:59 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

Greg wrote:
Quote:
deb (AT) pixar (DOT) com wrote:
Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....



Sutter's and Alexandrescu's "C++ Coding Standards" offers similar
advice: favoring abstract classes when inheriting. Regardless of its
endorsements, the advice itself is absolutely sound.

I really do not like this advice. Nor do I think it sound.

Quote:
The difficulty presented when inheriting from a concrete class is
meeting the requirement of substitutability. The derived class must be
able to stand in for the base class everywhere the base class could be
used. When the base is an abstract class, this means that the derived
class must adhere to an interface, but when the base class is concrete
the derived class must adhere to both an interface and an
implementation. The derived class is often overly constrained in this
situation because its implementation must continue to meet the clients'
expectations that have been set by the base class's implementation. But
it is difficult often just to identify those expectations, much less
respect them while trying at the same time to differ from the base
class in some appreciable way

In a language where objects are always accessed with pointers and there
is no possibility of slicing (like Java), I do not feel
substitutability is ever a problem for concrete classes. In a more
powerful language like C++, the power of the language should not be a
hindrance to design. Just have a look at the famous class hierachies
whether there are non-leaf concrete classes. And imagine whether you
like std::exception or std::logic_error to be abstract just because
they will be inherited!

Best regards,

Yongwei


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Palik Imre
Guest





PostPosted: Wed Aug 17, 2005 10:03 am    Post subject: Re: design question: deriving from a concrete class Reply with quote

"Greg" <greghe (AT) pacbell (DOT) net> writes:

Quote:
deb (AT) pixar (DOT) com wrote:
Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....

Sutter's and Alexandrescu's "C++ Coding Standards" offers similar
advice: favoring abstract classes when inheriting. Regardless of its
endorsements, the advice itself is absolutely sound.

They are also saying "Consider making virtual functions nonpublic, and
public functions nonvirtual". This seems to go somewhat against
abstract base classes.

Quote:
The difficulty presented when inheriting from a concrete class is
meeting the requirement of substitutability.

If all the public methods are nonvirtual, then it is hard not to meet
those requirement.

Quote:
The derived class must be
able to stand in for the base class everywhere the base class could be
used.

When one derives from an abstract base, then, using the same measure,
all the derived classes must be substitutable. Or else they can wreak
havoc in their users' code. With a concrete base, one has at least a
reference implementation.


ImRe

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
j
Guest





PostPosted: Wed Aug 17, 2005 11:17 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote


"Palik Imre" <clcppm-poster (AT) this (DOT) is.invalid> wrote

Quote:
"Greg" <greghe (AT) pacbell (DOT) net> writes:

[email]deb (AT) pixar (DOT) com[/email] wrote:
Victor Bazarov writes:
Where did you read that nonsense?

[Referring to: I 've read many times that when writing a base class
you expect people to derive from, the class should be abstract.]

Item 33: "Make non-leaf classes abstract."
More Effective C++.

Oh, Scott? ....

Sutter's and Alexandrescu's "C++ Coding Standards" offers similar
advice: favoring abstract classes when inheriting. Regardless of its
endorsements, the advice itself is absolutely sound.

They are also saying "Consider making virtual functions nonpublic, and
public functions nonvirtual". This seems to go somewhat against
abstract base classes.

No - not really - this gives the author of the base class some
possibilities.

Making sure the base class is always accessed through a baseclass member
function allows derivees to implement protected virtual functions... And the
base class implementer can make sure something is always done before and/or
after the virtual function call... That can be something like setting up the
"window" for drawing in, or making sure there is a certain file or what ever
is needed by the derivees function... If you just make a virtual function
public, you cannot make these kind of niceties...
(This is important when you build long living frameworks, where you cannot
allow the interface to change. Implementation details can change due to OS
changes or a change in another library...)


Quote:

The difficulty presented when inheriting from a concrete class is
meeting the requirement of substitutability.

If all the public methods are nonvirtual, then it is hard not to meet
those requirement.

The derived class must be
able to stand in for the base class everywhere the base class could be
used.

When one derives from an abstract base, then, using the same measure,
all the derived classes must be substitutable. Or else they can wreak
havoc in their users' code. With a concrete base, one has at least a
reference implementation.

By making a "reference" implementation you must be sure that no matter what
set of virtual functions the user chooses to implement, the new class will
still be valid... If they are all pure virtual functions, the implementor of
the derivee will have to decide for each function, how they will be
implemented.

A reference implementation should be another class inheriting from the
abstract class (in my opinion).
Leaving some functions virtual and implemented, can easily mislead the
implementor of a derivee. I try never to do "default" implementations, since
there seldom seems to be a good default implementation.
please consider: If you have a shape base class, what would the "default"
implementation of the
"virtual double Area()" function be??? Something like {return 0.0;};?? And
how often would that end up being the wrong implementation?? If that
function was pure virtual, the compiler would complain if it was not
considered during the implementation of a derivee.. That would make it so
much easier figuring out why all polygons seems to have an area of 0.0.....
Smile
[excess quoting deleted --mod]
Jesper Madsen, SAXoTECH

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Viper Craft
Guest





PostPosted: Thu Aug 18, 2005 1:10 pm    Post subject: Re: design question: deriving from a concrete class Reply with quote


[email]deb (AT) pixar (DOT) com[/email] писал(а):

Quote:
Thoughts?


I think you can use "Visitor" pattern for your task...

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.