Hi,
I have the following problem. I have an interface (abstract base class)
to represent a "device":
class IDevice {
virtual Read () = 0;
}
I have a number of concrete devices, that implement this interface. The
typical implementation of a device consist of a protocol part (defines
how to read the data) and a layout part (defines the structure of the
data and thus where to read the data):
class Device : IDevice {
m_protocol;
m_layout;
...
}
Device::Device ()
: m_protocol (...), m_layout (...)
{
...
}
Device::Read ()
{
return m_protocol->Read (m_layout->offset);
}
But now I want to implement some devices which are very similar. For
instance two devices sharing the same layout, but using a different
protocol. What is the preferred way to implement this, without
duplicating all code?
Basically, only the constructor is different. All other member functions
(such as Read) have exactly the same implementation.
ADevice::ADevice ()
: m_protocol (new AProtocol (...)), m_layout (new Layout (...))
{
...
}
BDevice::BDevice ()
: m_protocol (new BProtocol (...)), m_layout (new Layout (...))
{
...
}
Thanks in advance,
Jef
|
|
0
|
|
|
|
Reply
|
Jef
|
1/8/2010 1:03:49 PM |
|
> Basically, only the constructor is different. All other member functions
> (such as Read) have exactly the same implementation.
If I understand this problem correctly, you might be able to put an
optional parameter in your constructor which identifies which way to
construct the object, depending on whichever device you need to use.
|
|
0
|
|
|
|
Reply
|
McColgst
|
1/8/2010 2:38:04 PM
|
|
On Jan 8, 8:38=A0am, McColgst <mccol...@gmail.com> wrote:
> > Basically, only the constructor is different. All other member function=
s
> > (such as Read) have exactly the same implementation.
>
> If I understand this problem correctly, you might be able to put an
> optional parameter in your constructor which identifies which way to
> construct the object, depending on whichever device you need to use.
Yeah. If you want to win at amateur hour.
sherm--
|
|
0
|
|
|
|
Reply
|
Sherm
|
1/8/2010 2:40:25 PM
|
|
In article <hi7ag1$8pk$1@ikarus.fw.belnet.be>,
jefdriesen@hotmail.com.invalid says...
[ ... ]
> But now I want to implement some devices which are very similar.
> For instance two devices sharing the same layout, but using a
> different protocol. What is the preferred way to implement this,
> without duplicating all code?
>
> Basically, only the constructor is different. All other member functions
> (such as Read) have exactly the same implementation.
From the looks of things, you could use a template:
template <class protocol, class layout>
class Device {
protocol m_protocol;
layout m_layout;
public:
Device() : m_protocol(new protocol), m_layout(new layout) {}
};
Device<AProtocol, ALayout> ADevice;
Device<BProtocol, BLayout> BDevice;
It doesn't sound like you need the other possibility, which would be
that you don't know the combination of protocol and layout until run
time. If you did need to do that, you'd probably want the device to
store a reference (or pointer) to its associated layout and protocol,
and have a factory class to look at the data and create a device
object with the correct layout and protocol for that data.
--
Later,
Jerry.
|
|
0
|
|
|
|
Reply
|
Jerry
|
1/8/2010 10:24:24 PM
|
|
Jef Driesen wrote:
> Basically, only the constructor is different. All other member functions
> (such as Read) have exactly the same implementation.
That's exactly what inheritance was invented for. You create a base
class which contains the common functionality, and then specialize from
it. In your case, it would be something like this (rename the classes to
more descriptive names):
class IDeviceWithCommonFunctionality: public IDevice
{
public:
virtual Read(); // The common implementation
};
class ADevice: public IDeviceWithCommonFunctionality
{
public:
ADevice(); // constructor
};
class BDevice: public IDeviceWithCommonFunctionality
{
public:
BDevice(); // constructor
};
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
|
|
0
|
|
|
|
Reply
|
Juha
|
1/9/2010 11:30:36 AM
|
|
Jerry Coffin wrote:
> From the looks of things, you could use a template:
Isn't that a bit of a far-fetched solution for something which is
exactly what inheritance was invented for?
He wants classes with common functionality, except for the
constructor, which is specialized for each class. That's exactly what
inheritance is for.
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
|
|
0
|
|
|
|
Reply
|
Juha
|
1/9/2010 11:32:18 AM
|
|
"Juha Nieminen" <nospam@thanks.invalid>
> Jerry Coffin wrote:
>> From the looks of things, you could use a template:
>
> Isn't that a bit of a far-fetched solution for something which is
> exactly what inheritance was invented for?
far-fetched? The request mapped perfectly to what templates do, and Jerry
showed the code that gives the perfect solution (to what was stated).
Inheritance was invented for a different thing, and would solve this case in
a contorted way if at all -- and OP seem to be familiar with it enough, and
turned here discovering the redundancy it leaves.
> He wants classes with common functionality, except for the
> constructor, which is specialized for each class. That's exactly what
> inheritance is for.
Care to show an example?
And in current C++ you can not inherit constructors, so how that would be
handled?
The classes' "common functionality" is really common just textually -- it
invokes different functions on objects of different types.
Inheritance could deal with the "different function" thing calling a
virtual, but is hosed with the different member.
Certainly the class could have parts that are
|
|
0
|
|
|
|
Reply
|
Balog
|
1/9/2010 3:07:27 PM
|
|
On 09/01/10 12:30, Juha Nieminen wrote:
> Jef Driesen wrote:
>> Basically, only the constructor is different. All other member functions
>> (such as Read) have exactly the same implementation.
>
> That's exactly what inheritance was invented for. You create a base
> class which contains the common functionality, and then specialize from
> it. In your case, it would be something like this (rename the classes to
> more descriptive names):
>
> class IDeviceWithCommonFunctionality: public IDevice
> {
> public:
> virtual Read(); // The common implementation
> };
>
> class ADevice: public IDeviceWithCommonFunctionality
> {
> public:
> ADevice(); // constructor
> };
>
> class BDevice: public IDeviceWithCommonFunctionality
> {
> public:
> BDevice(); // constructor
> };
The problem with this approach is that the common code needs access to
the protocol and layout. And if those are made members of the concrete
classes, the common classes don't have access to them. But if you store
them in the common class, the common class can't initialize them
properly, because only the concrete classes have that knowledge to
choose the appropriate protocol and layout.
|
|
0
|
|
|
|
Reply
|
Jef
|
1/9/2010 7:14:23 PM
|
|
On 08/01/10 23:24, Jerry Coffin wrote:
> In article<hi7ag1$8pk$1@ikarus.fw.belnet.be>,
> jefdriesen@hotmail.com.invalid says...
>
> [ ... ]
>
>> But now I want to implement some devices which are very similar.
>> For instance two devices sharing the same layout, but using a
>> different protocol. What is the preferred way to implement this,
>> without duplicating all code?
>>
>> Basically, only the constructor is different. All other member functions
>> (such as Read) have exactly the same implementation.
>
> From the looks of things, you could use a template:
>
> template<class protocol, class layout>
> class Device {
> protocol m_protocol;
> layout m_layout;
> public:
> Device() : m_protocol(new protocol), m_layout(new layout) {}
> };
>
> Device<AProtocol, ALayout> ADevice;
> Device<BProtocol, BLayout> BDevice;
>
> It doesn't sound like you need the other possibility, which would be
> that you don't know the combination of protocol and layout until run
> time. If you did need to do that, you'd probably want the device to
> store a reference (or pointer) to its associated layout and protocol,
> and have a factory class to look at the data and create a device
> object with the correct layout and protocol for that data.
Templates are not an option in my case for two reasons:
First, the constructor for different protocol/layout objects can be
different (e.g. different number of arguments, different types, etc),
and the code in the constructor is also not the same for each device.
Second, my actual implementation is not in C++, but in plain C (for
portability reasons). I do have an object oriented framework where
inheritance and polymorphism is done with structs and manual vtable's,
but templates is simply not possible. I posted to a C++ newsgroup
because I design in C++ and then port the concept to my C environment.
It's easier to visualize the concept without the C oop boilerplate code.
|
|
0
|
|
|
|
Reply
|
Jef
|
1/9/2010 7:30:48 PM
|
|
Am 09.01.2010 20:14, schrieb Jef Driesen:
> On 09/01/10 12:30, Juha Nieminen wrote:
>> Jef Driesen wrote:
>>> Basically, only the constructor is different. All other member functions
>>> (such as Read) have exactly the same implementation.
>>
>> That's exactly what inheritance was invented for. You create a base
>> class which contains the common functionality, and then specialize from
>> it. In your case, it would be something like this (rename the classes to
>> more descriptive names):
>>
>> class IDeviceWithCommonFunctionality: public IDevice
>> {
>> public:
>> virtual Read(); // The common implementation
>> };
>>
>> class ADevice: public IDeviceWithCommonFunctionality
>> {
>> public:
>> ADevice(); // constructor
>> };
>>
>> class BDevice: public IDeviceWithCommonFunctionality
>> {
>> public:
>> BDevice(); // constructor
>> };
>
> The problem with this approach is that the common code needs access to
> the protocol and layout. And if those are made members of the concrete
> classes, the common classes don't have access to them. But if you store
> them in the common class, the common class can't initialize them
> properly, because only the concrete classes have that knowledge to
> choose the appropriate protocol and layout.
Read about Dependency injection, i.e.:
http://en.wikipedia.org/wiki/Dependency_injection
In short, you pass a pointer/reference of a specific service
implementation to a class, so that the class doesn't have to create it,
and doesn't even have to know about it's existance (only the abstract base).
class BasicDevice : public IDevice
{
public:
virtual Read() { /* ... */ }; // common implementation
protected:
// this class can't be instantiated directly
BasicDevice(layout& l, protocol& p)
: m_layout(&l), m_protocol(&p) {}
private:
ILayout* m_layout;
IProtocol* m_protocol;
}
class SpecificDevice : public BasicDevice
{
public:
ADevice() : BasicDevice(m_layout, m_protocol) {}
private:
SomeLayout m_layout;
SomeProtocol m_protocol;
};
You can also allocate the layout & protocol on the heap, if BasicDevice
handles deallocation.
--
Thomas
|
|
0
|
|
|
|
Reply
|
Thomas
|
1/9/2010 7:38:40 PM
|
|
In article <hi9pg3$1gc1$2@adenine.netfront.net>,
nospam@thanks.invalid says...
>
> Jerry Coffin wrote:
> > From the looks of things, you could use a template:
>
> Isn't that a bit of a far-fetched solution for something which is
> exactly what inheritance was invented for?
>
> He wants classes with common functionality, except for the
> constructor, which is specialized for each class. That's exactly what
> inheritance is for.
An inheritance-based solution is exactly what I was thinking of when
I said:
It doesn't sound like you need the other possibility, which
would be that you don't know the combination of protocol
and layout until run time. [ ... ]
In a case like that, you'd have a hierarchy of layouts and a
hierarchy of protocols, and the ctor for your device class would take
a reference (or pointer) to a layout and a protocol. You'd then store
those pointers/references in the device class.
This introduces some extra complexity (e.g. managing the lifetimes of
the protocol and layout objects) and run-time overhead (all the
functions in the layout/protocol that are used from the device need
to be virtual). Neither of these is huge, and both are quite
manageable. If you needed (or had some use for) the capabilities you
get from them, they'd be entirely worthwhile and reasonable. Given
that (at least according to the OP) the idea in this case was purely
to minimize duplication in the source code, _they_ are the solution
I'd call far-fetched.
There is an inheritance-based solution that eliminates most of those
problems as well. In fact, I'd consider it quite similar to the
template-based one I posted previously. It would be something like:
class ALayout {};
class BLayout {};
class AProtocol {};
class BProtocol {};
class ADevice : ALayout, AProtocol {};
class BDevice : BLayout, BProtocol {};
For those to whom that might look a bit unusual, that's multiple,
private inheritance. It does much the same as the template-based
solution: it embeds an instance of a protocol and a layout in each
device class. It has many of the same strengths and weaknesses as the
template-based version as well: each combination of protocol and
layout used to implement a device must be specified at compile time,
not at run time. There is no need for the functions to be virtual,
because we're never invoking them via a pointer/reference to the
base. Lifetime issues are trivial -- each protocol and layout pair is
created/destroyed along with the device class (i.e., just like any
other base class).
During the time after C++ got MI, but before it got templates, I
probably would have recommended this solution. Today, however, I see
little or no advantage to it over the template-based one I posted
originally.
--
Later,
Jerry.
|
|
0
|
|
|
|
Reply
|
Jerry
|
1/9/2010 9:24:53 PM
|
|
On Jan 9, 3:10 pm, "Balog Pal" <p...@lib.hu> wrote:
> "Juha Nieminen" <nos...@thanks.invalid>
> > Jerry Coffin wrote:
> >> From the looks of things, you could use a template:
> > Isn't that a bit of a far-fetched solution for something
> > which is exactly what inheritance was invented for?
> far-fetched? The request mapped perfectly to what templates
> do, and Jerry showed the code that gives the perfect solution
> (to what was stated).
> Inheritance was invented for a different thing, and would
> solve this case in a contorted way if at all -- and OP seem to
> be familiar with it enough, and turned here discovering the
> redundancy it leaves.
I wouldn't say that inheritance was invented for this, but using
inheritance to provide "custom" initialization is a more or less
standard C++ idiom, and hardly what one would consider
contorted. (You might start by looking at something like
std::fstream, for example.)
Templates are an alternative solution. They have the
disadvantage that they can easily lead to code bloat, and that
to be effective, the initializations have to share a common
pattern; inheritance gives you a lot more freedom. On the other
hand, to use inheritance, you have to make everything needed by
the derived classes available somehow: either protected or via
an accessor function. There's no universally correct solution,
but on the whole, I find that inheritance provides the simpler
solution most of the time.
> > He wants classes with common functionality, except for the
> > constructor, which is specialized for each class. That's
> > exactly what inheritance is for.
> Care to show an example?
class Device
{
Protocol* my_protocol;
Layout* my_layout;
public:
Device( Protocol* desired_protocol,
Layout* desired_layout )
: my_protocol( desired_protocol )
, my_layout( desired_layout )
{
}
// ...
};
class SomeSpecificDevice
: private SpecificProtocol // inheritance to control
, private SpecificLayout // order of initialization.
, public Device
{
public:
SomeSpecificDevice() : Device( this, this ) {}
};
> And in current C++ you can not inherit constructors, so how
> that would be handled?
See above. It's a fairly standard idiom.
Of course, you can easily combine the two, using a template for
the derived class (parametrized on the protocol and the layout).
The derivation still gives you the liberty of handling special
cases differently, however.
> The classes' "common functionality" is really common just
> textually -- it invokes different functions on objects of
> different types.
The original code looked to me more of something along the lines
of the strategy pattern. Where inheritance plays an important
role in the stragety classes.
> Inheritance could deal with the "different function" thing
> calling a virtual, but is hosed with the different member.
> Certainly the class could have parts that are
Looks like something got deleted here.
--
James Kanze
|
|
0
|
|
|
|
Reply
|
James
|
1/9/2010 11:24:05 PM
|
|
"James Kanze" <james.kanze@gmail.com>
> I wouldn't say that inheritance was invented for this, but using
> inheritance to provide "custom" initialization is a more or less
> standard C++ idiom, and hardly what one would consider
> contorted.
Well, "contorted" may be the wrong word, I mean it leads to way more work
and way more complexity, if actually chosen.
> Templates are an alternative solution. They have the
> disadvantage that they can easily lead to code bloat, and that
> to be effective, the initializations have to share a common
> pattern; inheritance gives you a lot more freedom. On the other
> hand, to use inheritance, you have to make everything needed by
> the derived classes available somehow: either protected or via
> an accessor function.
Exactly. In the described case it needs converting the concrete classes to
interfaces.
> There's no universally correct solution,
> but on the whole, I find that inheritance provides the simpler
> solution most of the time.
Solution to what requirements? If you need runtime polymorphism, sure, you
go that way. If compile-time stuff is good, then it is a drag, and
disadvantage.
>> Care to show an example?
>
> class Device
> {
> Protocol* my_protocol;
> Layout* my_layout;
In the original case there was ProtocolA, ProtocolB, no generic Protocol was
mentioned usable that way. Certainly it is possible to design the syste
that way up front, or convert like that, but would you do it unless
necessary?
> class SomeSpecificDevice
> : private SpecificProtocol // inheritance to control
> , private SpecificLayout // order of initialization.
> , public Device
> {
> public:
> SomeSpecificDevice() : Device( this, this ) {}
> };
With what you're back to 'repeated code' the original question was
concerned. To make it good you go ahead to make that class a template, and
use like in Jerry's #1 variant.
But then is there a real point to do the split, and fidding with the base
instead of the direct approach? You certainly still may want a base
class, if there are parts independent of the variable elements.
the original mentioned just simple calls that is hardly code bloat -- if
that is a real concern (and the template visibly has fat functions that are
mostly indepentent, a few virtuals may be defined and the bulk moved to the
base.
But that adds complexity, so only if there is a good reason.
>> And in current C++ you can not inherit constructors, so how
>> that would be handled?
>
> See above. It's a fairly standard idiom.
I'm certainly aware of this way, and used it too, thought something
different is meant.
> Of course, you can easily combine the two, using a template for
> the derived class (parametrized on the protocol and the layout).
> The derivation still gives you the liberty of handling special
> cases differently, however.
Sure.
>> The classes' "common functionality" is really common just
>> textually -- it invokes different functions on objects of
>> different types.
>
> The original code looked to me more of something along the lines
> of the strategy pattern. Where inheritance plays an important
> role in the stragety classes.
IMO strategy, as defined in the original form is mainly used for
runtime-changing situations. Especially in C++, where the static cases are
handled better using 'policy' or 'traits'. To me strategy implies I want
to assembe and possibly change it at runtime.
|
|
0
|
|
|
|
Reply
|
Balog
|
1/10/2010 12:27:14 AM
|
|
On 2010-01-08, Jef Driesen <jefdriesen@hotmail.com.invalid> wrote:
> Hi,
>
> I have the following problem. I have an interface (abstract base class)
> to represent a "device":
>
> class IDevice {
> virtual Read () = 0;
> }
>
> I have a number of concrete devices, that implement this interface. The
> typical implementation of a device consist of a protocol part (defines
> how to read the data) and a layout part (defines the structure of the
> data and thus where to read the data):
>
> class Device : IDevice {
> m_protocol;
> m_layout;
> ...
> }
>
> Device::Device ()
> : m_protocol (...), m_layout (...)
> {
> ...
> }
>
> Device::Read ()
> {
> return m_protocol->Read (m_layout->offset);
> }
>
> But now I want to implement some devices which are very similar. For
> instance two devices sharing the same layout, but using a different
> protocol. What is the preferred way to implement this, without
> duplicating all code?
Use aggregation for the protocol and layout rather than composition.
It almost looks like your Device class is just an empty facade that
delegates its operations to the m_protocol and m_layout that it
contains.
These members can just be references (to base classes which have
virtual functions).
The IDevice interface binds to Device, which proxies all of the calls to
these other objects. A Device instance can appear to be of effectively
different types because it can have references to different types of
protocols and layouts.
> Basically, only the constructor is different. All other member functions
> (such as Read) have exactly the same implementation.
>
> ADevice::ADevice ()
> : m_protocol (new AProtocol (...)), m_layout (new Layout (...))
> {
> ...
> }
>
> BDevice::BDevice ()
> : m_protocol (new BProtocol (...)), m_layout (new Layout (...))
> {
> ...
> }
So they already are pointers? You are one step away:
Device::Device(ProtocolBase *proto, LayoutBase *layout)
: m_protocol(proto)
, m_layout(layout)
{
}
Now it's up to whoever is constructing this object to configure it
with an appropriate combination of protocol and layout.
This is where the class factory pattern comes in handy.
// derives from IDeviceFactory
// makes devices configured with AProtocol and ALayout
static ADeviceFactory adf;
// factoryPtr points to some IDeviceFactory implementation;
// just call the Create virtual function to make a factory of
// its kind.
Device *dev = factoryPtr->Create();
|
|
0
|
|
|
|
Reply
|
Kaz
|
1/10/2010 4:30:05 AM
|
|
In article <IP42n.37647$J64.12974@newsfe20.ams2>,
jefdriesen@hotmail.com.invalid says...
[ ... ]
> Templates are not an option in my case for two reasons:
>
> First, the constructor for different protocol/layout objects can be
> different (e.g. different number of arguments, different types, etc),
> and the code in the constructor is also not the same for each device.
>
> Second, my actual implementation is not in C++, but in plain C (for
> portability reasons). I do have an object oriented framework where
> inheritance and polymorphism is done with structs and manual vtable's,
> but templates is simply not possible. I posted to a C++ newsgroup
> because I design in C++ and then port the concept to my C environment.
> It's easier to visualize the concept without the C oop boilerplate code.
Yup, under those circumstances, it sounds like inheritance is nearly
the only possibility.
--
Later,
Jerry.
|
|
0
|
|
|
|
Reply
|
Jerry
|
1/10/2010 7:13:38 AM
|
|
On 09/01/10 20:38, Thomas J. Gritzan wrote:
> Am 09.01.2010 20:14, schrieb Jef Driesen:
>> On 09/01/10 12:30, Juha Nieminen wrote:
>>> Jef Driesen wrote:
>>>> Basically, only the constructor is different. All other member functions
>>>> (such as Read) have exactly the same implementation.
>>>
>>> That's exactly what inheritance was invented for. You create a base
>>> class which contains the common functionality, and then specialize from
>>> it. In your case, it would be something like this (rename the classes to
>>> more descriptive names):
>>>
>>> class IDeviceWithCommonFunctionality: public IDevice
>>> {
>>> public:
>>> virtual Read(); // The common implementation
>>> };
>>>
>>> class ADevice: public IDeviceWithCommonFunctionality
>>> {
>>> public:
>>> ADevice(); // constructor
>>> };
>>>
>>> class BDevice: public IDeviceWithCommonFunctionality
>>> {
>>> public:
>>> BDevice(); // constructor
>>> };
>>
>> The problem with this approach is that the common code needs access to
>> the protocol and layout. And if those are made members of the concrete
>> classes, the common classes don't have access to them. But if you store
>> them in the common class, the common class can't initialize them
>> properly, because only the concrete classes have that knowledge to
>> choose the appropriate protocol and layout.
>
> Read about Dependency injection, i.e.:
> http://en.wikipedia.org/wiki/Dependency_injection
>
> In short, you pass a pointer/reference of a specific service
> implementation to a class, so that the class doesn't have to create it,
> and doesn't even have to know about it's existance (only the abstract base).
>
> class BasicDevice : public IDevice
> {
> public:
> virtual Read() { /* ... */ }; // common implementation
>
> protected:
> // this class can't be instantiated directly
> BasicDevice(layout& l, protocol& p)
> : m_layout(&l), m_protocol(&p) {}
>
> private:
> ILayout* m_layout;
> IProtocol* m_protocol;
> }
>
> class SpecificDevice : public BasicDevice
> {
> public:
> ADevice() : BasicDevice(m_layout, m_protocol) {}
>
> private:
> SomeLayout m_layout;
> SomeProtocol m_protocol;
> };
>
> You can also allocate the layout& protocol on the heap, if BasicDevice
> handles deallocation.
This looks like a very interesting idea!
|
|
0
|
|
|
|
Reply
|
Jef
|
1/10/2010 7:35:26 AM
|
|
On 10/01/10 05:30, Kaz Kylheku wrote:
> On 2010-01-08, Jef Driesen<jefdriesen@hotmail.com.invalid> wrote:
>> Hi,
>>
>> I have the following problem. I have an interface (abstract base class)
>> to represent a "device":
>>
>> class IDevice {
>> virtual Read () = 0;
>> }
>>
>> I have a number of concrete devices, that implement this interface. The
>> typical implementation of a device consist of a protocol part (defines
>> how to read the data) and a layout part (defines the structure of the
>> data and thus where to read the data):
>>
>> class Device : IDevice {
>> m_protocol;
>> m_layout;
>> ...
>> }
>>
>> Device::Device ()
>> : m_protocol (...), m_layout (...)
>> {
>> ...
>> }
>>
>> Device::Read ()
>> {
>> return m_protocol->Read (m_layout->offset);
>> }
>>
>> But now I want to implement some devices which are very similar. For
>> instance two devices sharing the same layout, but using a different
>> protocol. What is the preferred way to implement this, without
>> duplicating all code?
>
> Use aggregation for the protocol and layout rather than composition.
>
> It almost looks like your Device class is just an empty facade that
> delegates its operations to the m_protocol and m_layout that it
> contains.
The real code is usually a little more complex. The one line example was
just to illustrate that the common code needs access to the protocol and
layout to do its job.
> These members can just be references (to base classes which have
> virtual functions).
>
> The IDevice interface binds to Device, which proxies all of the calls to
> these other objects. A Device instance can appear to be of effectively
> different types because it can have references to different types of
> protocols and layouts.
>
>> Basically, only the constructor is different. All other member functions
>> (such as Read) have exactly the same implementation.
>>
>> ADevice::ADevice ()
>> : m_protocol (new AProtocol (...)), m_layout (new Layout (...))
>> {
>> ...
>> }
>>
>> BDevice::BDevice ()
>> : m_protocol (new BProtocol (...)), m_layout (new Layout (...))
>> {
>> ...
>> }
>
> So they already are pointers? You are one step away:
>
> Device::Device(ProtocolBase *proto, LayoutBase *layout)
> : m_protocol(proto)
> , m_layout(layout)
> {
> }
They are not necessary pointers, but they could be if that would be
required for a particular solution. I didn't specify the type of the
m_protocol/layout members on purpose, to not rule out any idea from the
start. The use of new in the constructor was just to illustrate that for
an XDevice, a XProtocol is needed.
> Now it's up to whoever is constructing this object to configure it
> with an appropriate combination of protocol and layout.
>
> This is where the class factory pattern comes in handy.
>
> // derives from IDeviceFactory
> // makes devices configured with AProtocol and ALayout
>
> static ADeviceFactory adf;
>
> // factoryPtr points to some IDeviceFactory implementation;
> // just call the Create virtual function to make a factory of
> // its kind.
>
> Device *dev = factoryPtr->Create();
This appears to be very similar to the named constructor idiom [1], that
I have been looking at. Except that these named constructors are now
hidden behind the factory.
[1] http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8
|
|
0
|
|
|
|
Reply
|
Jef
|
1/10/2010 7:46:37 AM
|
|
Balog Pal wrote:
>> He wants classes with common functionality, except for the
>> constructor, which is specialized for each class. That's exactly what
>> inheritance is for.
>
> Care to show an example?
> And in current C++ you can not inherit constructors, so how that would
> be handled?
He wants classes with common functionality, except *for the
constructor*, which is *specialized* for each class.
In other words, he needs everything else to be the same *except for
the constructors*. Why would he even need to inherit constructors if
that's exactly what he is changing?
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
|
|
0
|
|
|
|
Reply
|
Juha
|
1/11/2010 8:04:30 PM
|
|
|
17 Replies
357 Views
(page loaded in 0.159 seconds)
Similiar Articles: stringstream (binary) performance problem - comp.lang.c++ ...Problem with pthreads C++ wrapper class on Linux - comp ... Best design for my classes to avoid code duplication ... stringstream (binary) performance problem - comp.lang ... Java Delegate and Visitor Pattern examples ... - comp.lang.java ...Best design for my classes to avoid code duplication? - comp.lang ... Care to show an example? And in current C++ you ... class is just an empty facade that delegates its ... Problem with pthreads C++ wrapper class on Linux - comp ...... There's something horrendously wrong in my thread class ... source code below and point out the errors in my code ... Program-wrapper to avoid multiple running instances ... OOP performance issues - comp.soft-sys.matlabBest design for my classes to avoid code duplication? - comp.lang ... I do have an object oriented framework where inheritance and polymorphism is done ... for my classes ... multiple inheritance usage - comp.soft-sys.matlabBest design for my classes to avoid code duplication? - comp.lang ... On the other hand, to use inheritance, you have to make everything needed by the ... How to implement exception handling in linux assembly? - comp.lang ...Best design for my classes to avoid code duplication? - comp.lang ... pthreads C++ wrapper class on Linux ... Exception Handling Best Practices in .NET - CodeProject Avoid ... Why can not I implicitly convert "Derived **" to "Base * const ...Best design for my classes to avoid code duplication? - comp.lang ... I have an interface (abstract base class) to ... And in current C++ you can not inherit constructors ... LQR DESIGN - comp.soft-sys.matlab[HELP]how to write matlab program using PI based on LQR - comp ... i want to know how ... Best design for my classes to avoid code ... Why should the following functions be ... Const constructor - comp.lang.c++.moderated... still don't understand how could one design a class that has copy ... Even the best of us make mistakes, it is ... your ArraySlice points to to > > avoid code duplication ... design pattern for a file converter... - comp.lang.java.programmer ...... anyone have any insight into the best design ... rest is just a record-by-record copy with your conversion code ... you to object-orient your own code. There are classes ... inserting class objects into maps - comp.lang.c++.moderated ...How do i insert a class into my map object along with a ... string as a key? > > here is bit of my code.(Team is my class ... of another handle class. ... any tricks to avoid ... Misuses of RTTI - comp.lang.c++.moderated... too lazy (or too incompetent) to design a workable class ... be written without goto, without code duplication ... stage which allows me to generate code for my (POD) classes ... Dos and don'ts in C++ unit testing? - comp.lang.c++.moderated ...You should try to avoid it whenever you can. For that, the best is to have as ... your responsibility and inproper class design ... for debugging when I *don't* design my code as ... ISO C++ forbids assignment of arrays - is there a way out ? - comp ...Typical case: a class "A" defined elsewhere (ie. not my code) which takes an ... Is "stack-based" object design for ref class really a ... produce the copy constructor & copy ... How to suppress template specialization? - comp.lang.c++.moderated ...... vectors in in a code based on STL and and MPI2 library routines. My ... size_t N> class bitset). If my assumptions are correct, than the best thing ... making a copy of the ... Don't repeat yourself - Wikipedia, the free encyclopediaDRY code is created by data transformation and code generators, which allows the software developer to avoid copy and paste operations. DRY code usually makes large ... 4.4 Web-Tier Application Framework Design... separates design concerns (data persistence and behavior, presentation, and control), decreasing code duplication ... servlets is best maintained in JavaBeans classes. Code ... 7/16/2012 4:59:27 AM
|