What I think I need is like a pure virtual function, except the base class does have an implementation which derived classes mustn't default to (and this rule must propagate). The opposite of final
?
I have a handful of types derived from a common base. The base is a useful type and some of the derived types are derived from other derived types. I'll be working with references to the base class only, but I need a virtual operator==()
which sees through this and calls hand-rolled comparisons appropriate to each situation. A sort of two-dimensional vtable for operator==()
.
It's important that implementations don't propagate to derived classes, because letting this happen accidentally could result in a comparison between incompatible types falling through to a base class implementation where they are compatible types and this could produce a false positive.
I mean to let specific functionally-equivalent cases compare equal despite them being expressed in different classes. I expect the problem extends to other operations, though, and perhaps my use of operator==()
isn't agreeable here.
I don't claim to know C++ -- I'm just a C hack trying to be idiomatic.
Here's what I've worked out so far:
class base;
class foo;
class bar;
class baz;
#define COMPARE public: \
virtual bool equal(base const &p) const; \
virtual bool equal(foo const &p) const; \
virtual bool equal(bar const &p) const; \
virtual bool equal(baz const &p) const; \
virtual bool operator==(base const &p) const { return p.equal(*this); }
class base {
int a_;
public:
base(int a) : a_(a) {}
COMPARE
};
class foo : public base {
int b_;
public:
foo(int a, int b) : base(a), b_(b) {}
COMPARE
};
class bar : public base {
int c_;
public:
bar(int a, int c) : base(a), c_(c) {}
COMPARE
};
class baz : public bar {
int d_;
public:
baz(int a, int c, int d) : bar(a, c), d_(d) {}
COMPARE
};
Now, thanks to COMPARE
, all T::equal()
must be implemented, and none of them are allowed to fall back on an earlier implementation. Also, every class has its own operator==()
which calls the appropriate equal()
for its own type (rather than the base class type).
What I want is to enforce these rules in the way that COMPARE
does now, but without needing to remember that every derived class has to reference the macro, and ideally (to be C++-idiomatic) without using a macro at all.
What's the proper C++ way to do this?
I'm also still learning, but what you describe sounds a lot like it might need a double dispatch and/or visitor pattern.
For double dispatch, something like:
This already looks a lot like the macro option presented above. :)
From TC++PL 4th edition, section 22.3.1 talking about double dispatch, there is mention of perhaps rather using a precomputed lookup table. Something like