virtual operator +

M

Maarten Kronenburg

Marteen,
The design you provide necessates that hash be performed outside the
class and be served as a parameter in the constructor. But in my
design, the hash string class itself should provide for computation of
hash. In essence by choosing a hash_string over a char_string , the
user is implying that i have a lot oc comparisons to do hence compare
the strings using the hash value. Usabilitry wise it would behave
identically to char_string. I had a desing using policy classes that
waorked , but the change in design necessated from the fact that a
common interface a.k.a a non-template base_string generic class would
be needed . Now i'm stuck with this overriding of virtual class wich
returns by value paradox. I'll go thrrough the NVI design pattern
hopefully to pick up some clue

If I understand correctly, the hash value is a function of the string
itself. In that case for the derived overridden member function add (with
argument ref base class) there would be no problem, because adding the
string with hash would mean first adding the strings themselves, and after
that recomputing the hash value, no matter if the argument was base or
derived. For the binary operator+ returning a base class object is also no
problem, because after that the operator= is called which calls the derived
overridden member function assign, where the hash is recomputed after the
strings are assigned. In other words, when the hash value is just a function
of the string values, it doesn't matter if they are sliced off, because they
can be recomputed. Unless you want to recompute the hash values from the
argument hash values, and not from the resulting string.
Regards, Maarten.
 
K

Kai-Uwe Bux

Hunk said:
Hi

I ws wondering if there is a way to implement operator+ in case of
virtual classes.
Here's the problem. I have to have a base string class from which two
classes (normal char string and a hash string class ) are derived. The
two derived classes are template classes specifying the sizes. The
base class is a non-template class so that it can be used generically
in the interface classes. the design would look like

class Base_string {
};

template<size>
class Char_string : Base_string {
};

template<size>
class Hash_string: Base_string{
};
So that in the interface class of the application he can use just the
generic Base_string to access the functions and doesnt have to know
whether its a Char or hash string
The issue is in implementing the operator+ . Since all the methods are
virtual in the base class and it should call the desired methods
polymorphically, operator+ is a challenge as it returns a Base_string
object
So if I have something like
Char_string<24> char_string1("Hello");
Char_string<24> char_string2("world");
Char_string<24> char_result;
Base_string* base_a = &char_string1;
Base_string* base_b = &char_string2;
Base_string* base_r = &char_result;

i wouldnt be able to do
*base_r = *base_a + *base_b; as the operator+ would return a
Base_object?
Any soultions to the above issue is most welcome

If it's just two derived classes, you might get away with something like
this:
#include <iostream>
#include <tr1/memory>
#include <cassert>


class Base {
public:

Base ( void ) {}

virtual
void some_method ( void ) const = 0;

};

class DerivedA : public Base {
public:

DerivedA ( void )
: Base()
{}

virtual
void some_method ( void ) const {
std::cout << "DerivedA\n";
}

};

class DerivedB : public Base {
public:

DerivedB ( void )
: Base ()
{}

virtual
void some_method ( void ) const {
std::cout << "DerivedB\n";
}

};


class Sum {

enum type { derived_a, derived_b };

typedef std::tr1::shared_ptr<Base> pointer;
pointer the_ptr;
type the_type;

public:

Sum ( Base const & lhs, Base const & rhs )
: the_ptr ()
{
if ( ( dynamic_cast<DerivedA const *>( &lhs ) != 0 )
&&
( dynamic_cast<DerivedA const *>( &rhs ) != 0 ) ) {
the_ptr = pointer( new DerivedA () );
the_type = derived_a;
}
if ( ( dynamic_cast<DerivedB const *>( &lhs ) != 0 )
&&
( dynamic_cast<DerivedB const *>( &rhs ) != 0 ) ) {
the_ptr = pointer( new DerivedB () );
the_type = derived_b;
}
assert( the_ptr != 0 );
}

operator Base & ( void ) {
return ( *the_ptr );
}

operator Base const & ( void ) const {
return ( *the_ptr );
}

operator DerivedA & ( void ) {
assert( the_type == derived_a );
return ( static_cast<DerivedA &>( *the_ptr ) );
}

operator DerivedA const & ( void ) const {
assert( the_type == derived_a );
return ( static_cast<DerivedA const &>( *the_ptr ) );
}

operator DerivedB & ( void ) {
assert( the_type == derived_b );
return ( static_cast<DerivedB &>( *the_ptr ) );
}

operator DerivedB const & ( void ) const {
assert( the_type == derived_b );
return ( static_cast<DerivedB const &>( *the_ptr ) );
}
void some_method ( void ) const {
the_ptr->some_method();
}

};

Sum operator+ ( Base const & lhs, Base const & rhs ) {
return ( Sum( lhs, rhs ) );
}

void test ( Base & b ) {
b.some_method();
}

int main ( void ) {
DerivedA a1;
DerivedA a2;
( a1 + a2 ).some_method();
DerivedA a;
a = a1 + a2;
DerivedB b1;
DerivedB b2;
test( b1 + b2 );
DerivedB b ( b1 + b2 );
}

The user-defined converions can lead to ambiguities, and there are probably
some other problems.

Question: what is the purpose of a common base class for these two string
types? Are users really supposed to use Base_string* polymorphically? If
you don't really need runtime polymorphism, the string classes could be
independent and common functionality can be supplied by templates and
overloaded functions.


Best

Kai-Uwe Bux
 
J

James Kanze

On Sep 12, 4:26 pm, James Kanze <[email protected]>
You are right... learnt it the hard way... you say there is
some way in letter/envelop idiom?

Yes. It gives value semantics with polymorphic behavior. But
there's no free lunch; it typically has a non-negligeable impact
on runtime, and significantly increases coupling between the
derived classes. (Of course, if you want to support binary
operators, you're going to have a lot of coupling between the
derived classes anyway, since you need some sort of double
dispatch.)
For now i have taken the decision to restrict the user to use
only +=. I know this is a very restrictive way , but for now
i know of no other way to tackle the issue.

Look up the letter/envelop idiom (originally from Coplien, if
I'm not mistaken). If performance isn't an issue, it should
solve the problem. (But if performance isn't an issue, why
bother having the length as part of the string type. The real
advantage in doing so is to avoid extra dynamic allocations, and
the letter/envelop idiom uses a lot of extra dynamic
allocations.)
Thats a good question. I would prefer giving a compilation
error for this.

In other words, you don't need a common base class, but maybe
(at most) implicit conversions.
This is for the simple reason that Hash_string data members
are different than Char_string. So would'nt know which to
return
The difference in Hash_string and Char_string is that the
Hash_string class has a hash value computed and stored as a
data member. So comparisons are faster as they would be
comparing integers rather than characters.

You still have to compare the characters, in order to ensure
equality. You only gain when most of the comparisons return not
equal. And depending on your value set, most comparisons
between non-equal strings may return false after only one or two
character comparisons. Using a hash value here is only useful
in a very few, specific cases: a fixed set of strings, for which
you can generate a perfect hash, or value sets where most, if
not all of the strings have a common prefix (URL's, for
example); in the latter case, if this is known, you can arrange
to start comparison after the common prefix, and only go back
and verify commonality if the rest is equal. (For URL's, and
for many other cases, if you start by comparing length, you'll
detect a lot of inequalities immediately.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top