|
Prev: Simulating new user-defined operators
Next: ANN: C++ cycliclogs library/commands is promoted to stable status
From: Vidar Hasfjord on 14 Apr 2008 03:51 In C++ you are allowed to declare an incomplete type (a "forward"). Code can operate on references and pointers to such types. This is a very nice feature with regard to encapsulation. I often use this feature to omit detail in interfaces; detail that not all clients need to know. For example: class Component { //... public: class Parameter; virtual Parameter* get_parameter (); }; Client code can use Component and even pass pointers to Parameters around while still being blissfully unaware of Parameter's definition. Clients that need to know can include a separate header where Parameter is defined. This works nicely except when the Parameter class really is private and clients only should see an abstract interface, i.e.: class Component { public: class IParameter { public: virtual string get_name () = 0; virtual string get_value () = 0; }; virtual IParameter* get_parameter (); }; Unfortunately, now the implementation of Component and friends, helper classes and free functions, no longer can use GetParameter without doing a dynamic_cast should it be necessary to access Parameter details. In other words, there is type erasure in the Component interface. It would be nice if it was possible to *partially* complete a type. This would mean to specify the base (or bases) of a type without providing the full definition. For example: class Component { public: class IParameter { //... }; class Parameter : public IParameter; // partial type completion virtual Parameter* get_parameter (); }; Now the compiler can do a full type-check against what is known about the Parameter type at any point in the code. The client code knows only that Parameter inherits IParameter and is hence restricted to use that interface, while the implementation code that has seen the full Parameter definition can use all its methods and members; without need for downcasting. Any views on the feasability of such a feature? Regards, Vidar Hasfjord -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alf P. Steinbach on 14 Apr 2008 12:23 * Vidar Hasfjord: > In C++ you are allowed to declare an incomplete type (a "forward"). > Code can operate on references and pointers to such types. This is a > very nice feature with regard to encapsulation. > > I often use this feature to omit detail in interfaces; detail that not > all clients need to know. For example: > > class Component { > //... > public: > class Parameter; > virtual Parameter* get_parameter (); > }; > > Client code can use Component and even pass pointers to Parameters > around while still being blissfully unaware of Parameter's definition. > Clients that need to know can include a separate header where > Parameter is defined. > > This works nicely except when the Parameter class really is private > and clients only should see an abstract interface, i.e.: > > class Component { > public: > class IParameter { > public: > virtual string get_name () = 0; > virtual string get_value () = 0; > }; > virtual IParameter* get_parameter (); > }; Are you sure you really want to hand out pointers, and raw pointers at that? > Unfortunately, now the implementation of Component and friends, helper > classes and free functions, no longer can use GetParameter without > doing a dynamic_cast should it be necessary to access Parameter > details. In other words, there is type erasure in the Component > interface. > > It would be nice if it was possible to *partially* complete a type. > This would mean to specify the base (or bases) of a type without > providing the full definition. For example: > > class Component { > public: > class IParameter { > //... > }; > class Parameter : public IParameter; // partial type completion > virtual Parameter* get_parameter (); > }; > > Now the compiler can do a full type-check against what is known about > the Parameter type at any point in the code. The client code knows > only that Parameter inherits IParameter and is hence restricted to use > that interface, So from the client code's point of view a Parameter has the same functionality as IParameter. Why not then use IParameter? > while the implementation code that has seen the full > Parameter definition can use all its methods and members; without need > for downcasting. > > Any views on the feasability of such a feature? Cheers, & hth., - Alf -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Greg Herlihy on 14 Apr 2008 12:26 On Apr 14, 11:51 am, Vidar Hasfjord <vattilah-gro...(a)yahoo.co.uk> wrote: > In C++ you are allowed to declare an incomplete type (a "forward"). > Code can operate on references and pointers to such types. This is a > very nice feature with regard to encapsulation. > > I often use this feature to omit detail in interfaces; detail that not > all clients need to know. For example: > > class Component { > //... > public: > class Parameter; > virtual Parameter* get_parameter (); > }; > > Client code can use Component and even pass pointers to Parameters > around while still being blissfully unaware of Parameter's definition. > Clients that need to know can include a separate header where > Parameter is defined. > > This works nicely except when the Parameter class really is private > and clients only should see an abstract interface, i.e.: > > class Component { > public: > class IParameter { > public: > virtual string get_name () = 0; > virtual string get_value () = 0; > }; > virtual IParameter* get_parameter (); > }; There is no reason to declare IParameter's virtual methods as pure - because the library does in fact provide implementations of those routines. Pure virtual methods necessitate that the client provide implementations - but there is no such requirement in this case. Instead, the Library interface should declare IParameter along these lines: class Component { public: ... class IParameter { public: virtual string get_name(); virtual string get_value(); }; virtual IParameter* get_parameter (); }; The Library then internally defines Component and IParameter subclasses: // Internal Library Class Declarations class ComponentImpl : public Component { class Parameter : public IParameter { public: Parameter() : IParameter() {} virtual ~Parameter() {} // ... }; virtual Parameter * get_parameter() { return new Parameter; } }; Essentially, the Library's factory method returns pointers to concrete subtypes of the Library's publicly-declared interface classes. In this way, the Library takes advantage of C++'s dynamic types and virtual method dispatch to furnish implementations without exposing irrelevant details. > It would be nice if it was possible to *partially* complete a type. > This would mean to specify the base (or bases) of a type without > providing the full definition. > ... The client code knows > only that Parameter inherits IParameter and is hence restricted to use > that interface, while the implementation code that has seen the full > Parameter definition can use all its methods and members; without need > for downcasting. The solution is for the Library to make only the "Parameter" class public - and to declare its "IParameter" subclass internally. > Any views on the feasability of such a feature? The C++ language already supports this behavior with virtual functions and dynamic types. Greg -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Marcin Swiderski on 15 Apr 2008 14:21 On 15 Kwi, 05:26, Greg Herlihy <gre...(a)mac.com> wrote: > > There is no reason to declare IParameter's virtual methods as pure - > because the library does in fact provide implementations of those > routines. Pure virtual methods necessitate that the client provide > implementations - but there is no such requirement in this case. > Virtual method should be declared as pure if there is no implementation provided in class definition. IParameter is just an interface and as such does not provide an implementation. If you won't declare it's methods as pure virtual, linker will fail. Cheers Sfider -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Vidar Hasfjord on 15 Apr 2008 18:57 On Apr 15, 4:26 am, Greg Herlihy <gre...(a)mac.com> wrote: > Instead, the Library interface should declare IParameter along these > lines: > class Component > [...] > virtual IParameter* get_parameter (); > [...] > class ComponentImpl : public Component > virtual Parameter* get_parameter () Yep, this will work due to covariant return types, which allows you to strengthen the type info. But it is a lot of scaffolding. A simpler solution is to just create two interfaces; one for external use and one for internal use: class Component { public: class IParameter {...}; virtual IParameter* get_parameter (); private: class Parameter; Parameter* private_get_parameter (); ... }; Implementation: class Component::Parameter : Component::IParameter { ... }; IParameter* Component::get_parameter () {return private_get_parameter ();} This works and has less implications on the Component class hierarchy compared to your solution. But it is still scaffolding. The interface of Component is duplicated and one implemented in terms of the other. It would be much more straight-forward to be able to tell the compiler partial type information. Here's that hypothetical solution again: class Component { public: class IParameter {...}; class Parameter : public IParameter; // partial type completion virtual Parameter* get_parameter (); private: ... }; But is it possible/easy to implement? Does the compiler know enough after seeing the partial type to use Parameter through the base class IParameter? Regards, Vidar Hasfjord -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
|
Next
|
Last
Pages: 1 2 Prev: Simulating new user-defined operators Next: ANN: C++ cycliclogs library/commands is promoted to stable status |