|
Prev: (Re) Constructing an object
Next: bind guard ?
From: francis_r on 28 Jul 2006 08:04 Dear newsgroup readers, When learning C++ I also studied Design Patterns because I figured that if C++ is an object oriented language I better start thinking the OO-way. I soon discovered that C++ really is a combination of OO, functional and generic programming. So I tried to expand my knowledge of these paradigms by learning other programming languages. And indeed learning Haskell really deepened my understanding of the STL (but I really miss lambda expressions now). Learning Ruby opened my eyes to the usefulness of iterators and each-loops (but I really miss closures now in C++). When programming in C++ I see now many more ways to write my code and I am left confused on how to proceed. With all these options available, what is the C++ way? Please share me your insights. Kind regards, Francis [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: jk on 28 Jul 2006 09:18 francis_r wrote: > When programming in C++ I see now many more ways to write my code and I > am left confused on how to proceed. With all these options available, > what is the C++ way? well in some stituations one or other technique usually stands out as the way to do it, so you just rust your judgement and do it that way. the tricky thing to realise is; if all options seem equally good, then your intuition is probably right here too and any of them will do, so just pick one (perhaps based on similarity to other parts of design) and stop worrying about it. if all options seem equally bad thaen thats usually a sign that you are missing something (either a pattern/idion or perhaps something in the design). [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: W. J. La Cholter on 28 Jul 2006 10:34 "francis_r" <francis.rammeloo(a)gmail.com> wrote in news:1154081437.672662.56150(a)m79g2000cwm.googlegroups.com: > Dear newsgroup readers, > > When learning C++ I also studied Design Patterns because I figured that > if C++ is an object oriented language I better start thinking the > OO-way. The Design Patterns book is a classic and fundamental for learning good design and C++ development. Given its age, I would caution that the example implementations do not represent best or good practices in many current environments. For example, compare its Singleton with that of Loki's. > I soon discovered that C++ really is a combination of OO, functional > and generic programming. So I tried to expand my knowledge of these > paradigms by learning other programming languages. And indeed learning > Haskell really deepened my understanding of the STL (but I really miss > lambda expressions now). Check out Boost Lambda. >Learning Ruby opened my eyes to the usefulness > of iterators and each-loops (but I really miss closures now in C++). > > When programming in C++ I see now many more ways to write my code and I > am left confused on how to proceed. With all these options available, > what is the C++ way? It's a balance between the needs of your project and best practices for your problem domain. Suppose you're developing a three-tiered application, involving data, business logic, and presentation (such as a typical web application). OO is a good way to implement the domain objects in the business layer. The classes are easy to model and translate into code. If there is commonality of operations, you might choose some generic techniques (if nothing else, by using STL). Hopefully, the data/business mapping layer can easily be mapped orthogonally with a third-party mapper/serializer. A functional approach could be best for the mapping because each mapping could be represented as a transform. Likewise, some of the user-interface presentation would be transform-dependent. On the other hand a model-view-controller (MVC) framework has many OO aspects in its implementation and interface. Leveraging these techniques where appropriate is sound engineering. For example, if you were to avoid generic practices for containers, then you'd be stuck with something like pre-Java generics for storing a collection of objects. Perhaps, everything would have to inherit from a common base class to be stored. If you try to use certain generic algorithms without functional Boost Lambda (or C++ TR1's implementation), you'd have to write ad-hoc functions to apply transforms across objects that don't quite fit the interface. If you implement your domain objects using a functional technique, you really wouldn't have a three-tiered architecture anymore. Some of the techniques are cutting edge, such as Boost Lambda. Therefore, you need to balance whether your platform and those looking at the code can support them. If you're building a GUI on a Microsoft platform, and you have a requirement to support MFC instead of ATL, you're stuck with its view of the world, circa 1997. No matter what understand the current best practices because they can help you avoid things like thread-unsafe singletons and brittle state machines. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: moleskyca1 on 28 Jul 2006 17:09 Thank you for sharing, I have learned from this post. W. J. La Cholter wrote: > For example, if you were to avoid generic practices for containers, > then you'd be stuck with something like pre-Java generics for storing > a collection of objects. Perhaps, everything would have to inherit > from a common base class to be stored. If you try to use certain > generic algorithms without functional Boost Lambda (or C++ TR1's > implementation), you'd have to write ad-hoc functions to apply > transforms across objects that don't quite fit the interface. If you > implement your domain objects using a functional technique, you really > wouldn't have a three-tiered architecture anymore. > This part is very interesting to me. I still have argument with java people about why is STL better than the pre-Java generics collection in Java. As you say, everything must inherit from a base in order to be in the collection. I know this is bad. Can you break it down for beginner/intermediate like me and others I argue with? Here is some pseudo-code (and C++ used to be like this pre-STL remember RougeWave RWCollection?). Why is line 25 so bad? Why forcing inheritance from Collectable is so bad? 1 // all must inherit from here to be in a Collection 2 class Collectable 3 { 4 virtual int comp(const Collectable *, const Collectable *) = 0; 5 }; 6 class Collection 7 { 8 public: 9 void add(Collectable *); 10 size_t size(); 11 Collectable *getAt(size_t); 12 }; 13 class Canvas; // forward declaration 14 class Shape: public Collectable 15 { 16 public: 17 virtual void draw(Canvas &) = 0; 18 19 }; 20 class Canvas 21 { 22 public: 23 void render(Collection &sc) { 24 for ( size_t i = 0; i < sc.size(); i++ ) 25 ((Shape *)sc.getAt(i))->draw(*this); 26 } 27 }; 28 class Rectangle: public Shape 29 { 30 public: 31 void draw(Canvas &) {;} // override to draw rectangle 32 }; 33 class Triangle: public Shape 34 { 35 public: 36 void draw(Canvas &) {;} // override to draw Triangle 37 }; 38 I have some reasons, but I could benefit from more detail and stronger reasons. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Carl Barron on 30 Jul 2006 13:00
<moleskyca1(a)yahoo.com> wrote: > > Thank you for sharing, I have learned from this post. > > > > W. J. La Cholter wrote: > > >> > > For example, if you were to avoid generic practices for containers, >> > > then you'd be stuck with something like pre-Java generics for storing >> > > a collection of objects. Perhaps, everything would have to inherit >> > > from a common base class to be stored. If you try to use certain >> > > generic algorithms without functional Boost Lambda (or C++ TR1's >> > > implementation), you'd have to write ad-hoc functions to apply >> > > transforms across objects that don't quite fit the interface. If you >> > > implement your domain objects using a functional technique, you really >> > > wouldn't have a three-tiered architecture anymore. >> > > > > This part is very interesting to me. I still have argument with java > > people about why is STL better than the pre-Java generics collection in > > Java. As you say, everything must inherit from a base in order to be in > > the collection. I know this is bad. Can you break it down for > > beginner/intermediate like me and others I argue with? Here is some > > pseudo-code (and C++ used to be like this pre-STL remember RougeWave > > RWCollection?). Why is line 25 so bad? Why forcing inheritance from > > Collectable is so bad? > > [code snipped] > > I have some reasons, but I could benefit from more detail and stronger > > reasons. > > It looks like you want a container of polymorphic Shape's. That said I created a base class suitable for boost::intrusive_ptr as I have an intruxive ptr with the same interface as boost's on this old compiler. // Shapes.h // forward declaration ok since we only use Canvas & in this header. class Canvas; class Shape { long count; // counter for reference counting protected: Shape(){} // prevent direct construction public: virtual void Draw(Canvas &) = 0; virtual ~Shape(){} // so derived class's dtor is called // functions for intrusive_ptr friend void intrusive_ptr_add_ref(Shape *p) {++(p->count);} friend void intrusive_ptr_release(Shape *p) { if(!--(p->count)) delete p; } }; class Rectangle:public Shape { public: void Draw(Canvas &); }; class Triangle:public Shape { public: void Draw(Canvas &); }; class Circle:public Shape { public: void Draw(Canvas &); }; // Collection.h #include <list> // for a list container vector or deque also work. #include "intrusive_ptr.h" // boost/intrusive_ptr.hpp in effect #include "Shapes.h" // namespace mine = boost; typedef std::list< mine::intrusive_ptr<Shape> > Collection; class Canvas { // simplest on this old compiler, various libs allow 'inline' // creation of this class render_one { Canvas &canvas; public: render_one(Canvas &a):canvas(a){} void operator () (mine::intrusive_ptr<Shape> x) { x->Draw(canvas); } }; public: void render(Collection &sc) { // walk the list std::for_each ( sc.begin(), sc.end(), render_one(*this) ); } }; this looks right and works if draw writes class name to std::cout. [driver and the implementations not included above] This looks like a safe implementation of a list of polymorphic objects. and is probably more efficient than an imitation of JAVA code in C++. I apologize if this was already in this thread... [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |