Sign in to follow this  
nerijus ramanauskas

Choosing and applying the best design pattern for the particular problem

Recommended Posts

Assume I have a template class named Sequence, which takes one template parameter. It's mainly for string buffers (or just strings) and stream buffers (unaligned byte arrays or just buffers). As it's real purpose's still undefined, we can't expect where else it could be used, it cannot even be partially specialized, although it has some methods that would only be used for strings, as well as Crop (or just sub_string), Trim, Strip, etc. But once again they can still be used somewhere else like in stream buffers (wanna play?), etc. Ok, enough introduction. The problem is about expanding/extending such the template class. Assume I want to write a specialization for the template class (ACTUALLY A DISCRETE CLASS THAT WILL JUST INHERIT THE BASE TEMPLATE CLASS `Sequence` (Sequence< char > in this particular situation)) by adding some merely-string-specific methods like Majuscule_latin_all, Compare_minuscule_latin, operator unsigned int( void ), etc. But here comes the problem and some other new problems: 1. If I want to just overload a method, I will also need to rewrite all the methods from the base class (from the template class `Sequence< char >` in this situation); 2. This is the main problem and the main purpose of this thread: if, for instance, Trim from the base class returns Sequence< char >, it is absolutely incompatible with that one class that I have "specialized" and what is more it returns the base class instance, so when users calls object_of_specialized_class.Trim() and expects it to return a new object of the same type from which user calls the method (in this case from the class we have "specialized"), it will fail and the user will start yelling with the anger it has caused. :-) What do you propose? Encapsulation? Inheritance won't help, as you see. Thanks in advance, anyway. // Wrote too fast, might be some mistakes, sorry.

Share this post


Link to post
Share on other sites
Have you considered... composition? Or using free functions?

I'm having a hard time figuring out what you are talking about. Can you post the classes in question? It sounds like Sequence is almost like vector<>.

Share this post


Link to post
Share on other sites
STL Sequence.

Note that it is not a hard class but a concept, implemented by most containers.

Algorithms to operate on the contents are in <algorithm>. They include all such trivialities as processing, trimming, cropping, etc....


General approach is often:
template < class I >
void foo(I beginItr, I endItr, params ...);



There is no need for inheritance or extension.

To specialize an operation based on certain type, the following always possible:

template < class T, class A >
void foo(
typename std::vector<T,A>::iterator beginItr,
typename std::vector<T,A>::iterator endItr);
This is equivalent to inheriting vector and overloading its foo method, but expressed with compile-time polymorphism (aka templates).

Template polymorphism is resolved during compile time via specializations, run-time polymorphism (aka inheritance) is orthogonal and often undesirable at this level.

Share this post


Link to post
Share on other sites
I am not even talking about STL. Sequence is somekind of container only for string and stream buffers (and maybe somewhere else, if you wanna play). I am talking about my own `Sequence` class, not about the STL one. :-)

The problem is that if I inhert the base class and if that class has some methods that return some new objects of the same class, return type won't change if I inhert that base class. I mean if my base class is:
template< Type_ >

class Sequence
{
public:
Sequence< Type_ > Trim( .... );
};


And my "child" is:

class String: public Sequence< char >
{
public:
};


And when I create my new object:

String my_str;

my_str.Trim() will return Sequence< Type_ >, as we developers/programmers expected.

And here comes the problem. What should I do then? Should I encapsulate the object of the class Sequence< char > instead of inherting it? I am just confused right now, because making it virtual or inherting it will not solve the problem.

[Edited by - nerijus ramanauskas on March 16, 2010 9:35:57 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by nerijus ramanauskas
I am not even talking about STL. Sequence is somekind of container only for string and stream buffers (and maybe somewhere else, if you wanna play). I am talking about my own `Sequence` class, not about the STL one. :-)


And my reply was: "don't reinvent a completely solved problem".

Quote:
The problem is that if I inherting the base class and if that class has some methods that return some new objects of the same class, return type won't change if I inherting that base class.


There is a reason why STL containers are not meant to be extended, and many lessons learned. They expose exactly what is fixed, and provide all additional functionality as free functions based on common interface (::iterators).

Quote:
my_str.Trim() will return Sequence< Type_ >, as we developers/programmers expected.

This type of OO doesn't work all that well. Use in-place modification instead:
SomeSequenceType sst;
trim(sst);
// or, if original must be preserved
template < class T >
T trimcopy(T source) {
T result = source;
trim(result);
return result;
}


Since all of this is resolved during compile-time, there is no need for inheritance, typedefs will do, and they result in distinct types.

Quote:
So that means it's quite efficient to make my template class methods virtual?

No, no inheritance, no virtuals, no nothing. Just plain old functions operating on templated types.

See how STL is defined and how <algorithm>s work.

Share this post


Link to post
Share on other sites
Antheus, just noticed - this is it! (I thought you was talking only about some kinda STL containers, now I see it is just an example, isn't it?).
So that means it's quite efficient to make my template class methods virtual?

Share this post


Link to post
Share on other sites
.. So you all think that using free-functions is more efficient than using class-encapsulation? Oh, maybe: some "rich" templates and some "extensions" for it. Hmm... Yeah, baby! This is it! Thanks, finally realized that! ;-)

Share this post


Link to post
Share on other sites
Quote:

Ok, if, suppose, I want to overload the cast operator (operator signed int())?

This is almost never a good idea. It can cause all sorts of subtle bugs.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Quote:

Ok, if, suppose, I want to overload the cast operator (operator signed int())?

This is almost never a good idea. It can cause all sorts of subtle bugs.


And if I make it private (sorry, forgot to mention it), add some "friends" as well as static_cast (imagine it's just a template function that may be controlled by a user/developer), it will cause no sorts of problems.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerijus ramanauskas
And if I make it private (sorry, forgot to mention it), add some "friends" as well as static_cast (imagine it's just a template function that may be controlled by a user/developer), it will cause no sorts of problems.


This just adds two more kinds of problems.

Sequence really is a problem solved completely by STL.

Share this post


Link to post
Share on other sites
Quote:

...it will cause no sorts of problems.

It is your code base - you're the one who has to maintain it.

I'm not convinced you gain anything over having an explicit member function whose name describes the operation. Using static_cast is likely to take longer to write and still be less clear.

My impression from this thread is that you are maybe a little too eager to use some of the more obscure areas of C++, like implicit conversion operators and template specialisation, when there are clearer and simpler alternatives available. It might be worth thinking about what this buys you in the long run.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerijus ramanauskas
The problem is that if I inhert the base class and if that class has some methods that return some new objects of the same class, return type won't change if I inherting that base class.

Well, since you are specifically asking for a pattern, I'm gonna mention the Curiously recurring template pattern ;-)

Share this post


Link to post
Share on other sites
Ok, let's see:

template< typename Left_, typename Right_ >
Left_ Convert< Left_, Right_ >( const Right_& Convert_ )
{
return Left_( Convert_ );
}

class X
{
public:
// ...
private:
template< typename Left_, typename Right_ >
friend Left_ Convert< Left_, Right_ >( const Right_& Convert_ );

/* unsigned char* */ operator unsigned char*( void );
};

Let me see if there's a problem. /* global */ void /*::*/DoDoDo( unsigned char* ); DoDoDo( X() ); is not a problem, since it's not supported anyway if there's no explicit/public/etc cast operator.

Share this post


Link to post
Share on other sites
DevFred, this is really it! You've got a it! Danke!

I just, you know, hate STL and I think STL/C++ STD is extremely overdesigned. What I'm trying to do is to make it safe and clean to live in!

Extremely thankful for all you folks!
Have a nice day.

Share this post


Link to post
Share on other sites
Yay, ok. Free functions meet the best. Will use them. But (just for greater curiousity) what if C++ was an absolute OO programming lang just like C# is? Free functions ain't exist. Would use static methods? Could think of a better choice. Huh?

Danke.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerijus ramanauskas
Yay, ok. Free functions meet the best. Will use them. But (just for greater curiousity) what if C++ was an absolute OO programming lang just like C# is? Free functions ain't exist.
Thank God/Bjarne that ain't the case ;)
Though yeah you'd use static classes (you can pretend that the class owning the static methods is like a namespace in this case).

Share this post


Link to post
Share on other sites
Quote:
Original post by nerijus ramanauskas
But (just for greater curiousity) what if C++ was an absolute OO programming lang just like C# is?

Modern C# is not an "absolute OO" language either, it has functional ingredients as well. Being pure OO does not mean being good.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this