Some misc C++ questions (multimap, derived class function argument,virtual static)

D

Digital Puer

I have several C++ questions:

1. Why are the interfaces for multiset and multimap so complicated for
getting multiple values?

Instead of
multimap<Key, Value>

I usually prefer
map<Key, vector<Value> >

Isn't that much easier to use?


2. Suppose I have a base class that looks like:

class Base
{
public:
virtual void combine(const Base &other, Base &result) = 0;
}

class Derived : public Base
{
private:
string _name;
public:
void combine(const Derived &other, Derived &other) {}
}

When I try to instantiate Derived, g++ is telling me that the
pure virtual method Base.combine() is not implemented.
Why does Derived.combine() above not override Base.combine()?

Instead, I have to do some casting, like:

void combine(const Base &other, Base &result)
{
Derived &a = (Derived &)other;
string combination = _name + a._name;

((Derived &)result)._name = combination;
}

Is there a better approach?


3. For my abstract Base class, I want to specify a static "Factory"
method that produces a Base*:

class Base
{
virtual static Base* createRandomInstance();
}

I want to force all my Derived classes to provide such a factory
method that produces a Derived *.

However, apparently I cannot have a virtual static method
in C++ (or in Java). What is the best way to force that all
derived classes have such a factory method?
 
A

Alf P. Steinbach

* Digital Puer:
I have several C++ questions:

1. Why are the interfaces for multiset and multimap so complicated for
getting multiple values?

Instead of
multimap<Key, Value>

I usually prefer
map<Key, vector<Value> >

Isn't that much easier to use?

No opinion.

2. Suppose I have a base class that looks like:

class Base
{
public:
virtual void combine(const Base &other, Base &result) = 0;
}

class Derived : public Base
{
private:
string _name;
public:
void combine(const Derived &other, Derived &other) {}
}

When I try to instantiate Derived, g++ is telling me that the
pure virtual method Base.combine() is not implemented.
Why does Derived.combine() above not override Base.combine()?

Read up on the Liskov Substitution Principle.

Essentially if you could override that way you could then do

Derived d;
Base b;
Base& r = d;

r.combine( b, b );

where the Derived object gets Base objects in as arguments, but expects Derived
ones.

Instead, I have to do some casting, like:

void combine(const Base &other, Base &result)
{
Derived &a = (Derived &)other;
string combination = _name + a._name;

((Derived &)result)._name = combination;
}

Is there a better approach?

Don't cast.

E.g. you might add virtual member routines that give access to the name.

3. For my abstract Base class, I want to specify a static "Factory"
method that produces a Base*:

class Base
{
virtual static Base* createRandomInstance();
}

I want to force all my Derived classes to provide such a factory
method that produces a Derived *.

However, apparently I cannot have a virtual static method
in C++ (or in Java). What is the best way to force that all
derived classes have such a factory method?

Why not implement a generic factory that works for nearly all derived classes?

Like

template< class T >
T* createRandomInstance() { return new T(); }


class Derived: public Base
{
public:
Derived( char const [] ) {}
};

template<>
Derived* createRandomInstance<Derived>() { return new Derived(""); }


Base* p = createRandomInstance<Base>();

If the generic version works for a derived class, fine. If not, then using it
for a derived class probably won't compile. So then you've "forced" the derived
class to provide a specialization.


Cheers & hth.,

- Alf
 
F

Francesco

I have several C++ questions:

1. Why are the interfaces for multiset and multimap so complicated for
getting multiple values?

I don't find them that convolute... what is the part of the interface
that you don't like?
Instead of
multimap<Key, Value>

I usually prefer
map<Key, vector<Value> >

Isn't that much easier to use?

The two containers above are very similar but not interchangeable.

A multimap has its advantages on map, in this specific case. It allows
you to store separately two physically different keys which are just
logically equal to each other. If you don't need this peculiarity and
map fulfills your needs, you're perfectly fine using it.

Just my two cents, sorry for the other points but I should understand
them better before posting anything about them.

Cheers,
Francesco
 
D

Digital Puer

Specification and testing. Beyond that, why do you care? If someone
wants to derived from your class but not provide a factory, what harm
does it do?


Because I want to enforce the existence of a factory method
in all derived classes. Every derived class will have its own
data, and I want the class to be able to produce a Base *
though the factory. I would like this factory method to be
usable by a consumer of the Base class:

void consumer()
{
Base *randomItem = Derived::createInstance(); // factory
doSomething(randomItem);
}

You are right that I could write an English specification that
says that all derived classes must have a factory method,
but I want to have that enforced in the Base class.

I guess a better approach would be to move the factory method
into another class that knows about the Derived class.

void consumer(Factory &factory)
{
Base *randomItem = factory.createInstanceOfDerived();
doSomething(randomItem);
}
 
P

Paul N

However, apparently I cannot have a virtual static method
in C++ (or in Java).

I asked a similar question on 21 Mar 2008 - you can find it if you put
"gw7rib virtual static" into Google Groups and click "Search Groups".
Marcel Müller provided a solution to the problem I was having.

Hope this helps.
Paul.
 
J

Joshua Maurice

However, apparently I cannot have a virtual static method
in C++ (or in Java).

What would a "virtual static method" do?

Ex:

struct base { virtual void foo(); };
struct derived : base { virtual void foo(); };
int main()
{
derived d;
d.foo(); //calls derived::foo
derived* pd = &d;
pd->foo(); //calls derived::foo
base* pb = pd;
pb->foo(); //calls derived::foo

base b;
b.foo(); //calls base::foo
base* pb2 = &b;
pb2->foo(); //calls base::foo
}

In this example, which foo function is called depends upon the most-
derived type of the "this" object. If the most most-derived type of
the "this" object is "derived", then "derived::foo" is called. If the
most-derived type of the "this" object is "base", then "base::foo" is
called. Virtual functions require a "this" object. Static functions
forbid a "this" object. Thus it's not obvious what the semantics would
be for a "virtual static" function.
 

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
474,056
Messages
2,570,441
Members
47,119
Latest member
NoeliaIrby

Latest Threads

Top