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:
class base;
class foo;
class bar;
class baz;
class base {
int a_;
public:
base(int a) : a_(a) {}
virtual bool operator==(const base&) const =0;
virtual bool operator==(const foo&) const =0;
virtual bool operator==(const bar&) const =0;
virtual bool operator==(const baz&) const =0;
};
class foo : public base {
int b_;
public:
foo(int a,int b) : base(a),b_(b) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
class bar : public base {
int c_;
public:
bar(int a,int c) : base(a),c_(c) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
class baz : public bar {
int d_;
public:
baz(int a,int c,int d) : bar(a,c),d_(d) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
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
bool equal(const base& b1,const base& b2)
{
auto i = index(type_id(b1),type_id(b2));
return intersect_tbl[i](b1,b2);
}
except the base class does have an implementation which derived classes mustn't default to (and this rule must propagate)
If that is the only problem, then as Ben Voigt mentioned in his comment - it is not a problem, because pure virtual functions can be implemented.
Also, once a derived class overrides, I need the same rule in place,
that the override isn't used by further derived classes (if they must
then they can always call it explicitly in their own implementation)
If that is the case then "idiomatic C++ way" would probably be not to use inheritance to model "derived" - "further derived". Inheritance is typically used to model either substitutability or to model polymorphism, but it is neither here. In other words: model "derived" - "further derived" by composition.
So this appears to be one way of forcing derived classes to provide their own implementations of specific functions:
template<typename T> struct sweep : public T {
template <class... Args> sweep(Args&&... args) : T(args...) { }
virtual bool equal(base const &p) const = 0;
virtual bool equal(foo const &p) const = 0;
virtual bool equal(bar const &p) const = 0;
virtual bool equal(baz const &p) const = 0;
virtual bool operator==(base const &p) const = 0;
};
class base { ... };
class foo : public sweep<base> {
int b_;
public:
foo(int a, int b) : sweep(a), b_(b) {}
...
};
It still requires that the derived class remember to do something specific to constrain itself -- to use the sweep template to derive from the base class -- but it is at least C++ rather than C.
It also has the advantage that the template could refresh the default implementations rather than make them pure virtual; like so:
template<typename T> struct sweep : public T {
...
virtual bool equal(base const &p) const { return false; }
...
};
On the grounds that without further guidance every comparison should fail. This is actually closer to what I need -- but not what I asked for.
Related
I've read this, but that discussion is only about comparing operator that takes base or derived class as parameter. In my case I would like to inherit virtual operator for totally different parameter (std::string in this case) and I couldn't find even a discussion on this topic.
So in my case I have following code:
#include <string>
#include <iostream>
class Base {
public:
Base(std::string s) : str(s) {}
virtual bool operator==(const std::string& s) const { return s == str; };
protected:
std::string str;
};
class Derived : public Base {
public:
Derived(std::string s) : Base(s) {}
//bool operator==(const std::string& s) const override { return s == str; };
//bool operator==(const double& d) const { return d == doub; };
protected:
double doub;
};
int main() {
std::string foo = "foo";
Derived object(foo);
if (object == foo)
std::cout << "equal" << std::endl;
}
operator for string is correctly derived (code is compiling) in this case. But if I would like to define another operator, for type double (uncommenting second comment), code is not compiling, as compiler does not see operator for string defined in base class. Uncommenting first comment, i.e. explicitly overriding base's operator works again.
Can anyone explain such behaviour?
Lets say you have
class Derived : public Base {
public:
Derived(std::string s) : Base(s) {}
bool operator==(const double& d) const { return d == doub; };
protected:
double doub;
};
The problem here is that your Derived::operator== function hides the Base::operator== function.
This can be solved by pulling the operator== symbol from the Base class into the Derived class, with the using keyword:
class Derived : public Base {
public:
Derived(std::string s) : Base(s) {}
using Base::operator==; // Get the symbol from the Base class into the scope of the Derived class
bool operator==(const double& d) const { return d == doub; };
protected:
double doub;
};
I'm trying to create the following flow:
Having a 'Base' class, with no params or functionality, just so i can hold
Base pointers in a method.
Its derived class, is a template, which implements operator() on given template argument object type.
I'm trying, by using a pointer to base class, call the derived class operator(), in run-time.
I've tried implementing it using CRTP
(https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
But that doesn't seem to work the-other-way-around - when the derived class is a class template.
Here is my code:
class Base {};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const {
return (m_db.*m_func)(obj);
}
}
Now, usage is in another class template, that contains vector of Base class pointers, as follows, and have its own operator() :
template<typename Obj_Type2> /* Upon usage, Obj_Type2 is the same as Obj_Type, this is just to differ the two in the code here */
class BlaBla {
private:
std::vector<const Base *> m_vec;
public:
/* relevant constructors ... */
inline bool operator()(const Obj_Type2 &obj) const {
for(std::vector<const Base *>::const_iterator it = m_vec.begin(); it != m_vec.end(); ++it) {
/*** This is the problematic line V ***/
if( (*it).operator()(obj) ) { /* DO SOMETHING */ }
}
}
Of course the compiler is complaining that there is no matching function to call for in the problematic line that is marked in the code below, but i can't figure out a way to do the relevant call.
1st Solution that came to mind, is to create a virtual operator()(...), with a specific object type e.g. virtual operator()(const uint32_t &obj) in Base class, which works, but my intention is that operator()(...) will receive a variety of object types, and stating a virtual method for each of them is not elegant and seems to break all the template concept i want to implement here.
2nd Solution that came to mind, is somehow passing Ref_Obj and Obj_Type typenames to Base class, to be used in sort of interface method, that will use static_cast to call the appropriate Derived operator (As in CRTP) - But that doesn't seem to work because Derived class is a class template, and also BlaBla class doesn't directly know Ref_Obj typename.
Is there any other way to make the appropriate call to Deriver operator()
There is no clear clean way to do this. The fundamental problem is that there is no such thing as a virtual template method.
The cleanest way I can think of doing this that implements complete type erasure is with a dynamic cast, and a virtual method:
class Base {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Base& obj) const override {
const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj);
if (!derived_obj)
{
throw; // Or maybe return false, or something...
}
return (m_db.*m_func)(*derived_obj);
}
};
Obj_Type must also be derived from Base. This gets the job done at runtime, but there is no compile-time type-checking.
The other approach is to bite the bullet, and forego 100% type erasure:
template<typename Obj_Type>
class Base {
public:
virtual bool operator()(const Obj_Type &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base<Obj_Type> {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const override {
return (m_db.*m_func)(obj);
}
};
So, you can still abstract away operator() on some object to its pure interface, and define the details in the subclass.
Or, another alternative would be a combination of the two:
class SuperBase {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Obj_Type>
class Base : public SuperBase {
public:
virtual bool operator()(const Obj_Type &) const=0;
bool operator()(const Base &obj) const override
{
// Do the dynamic cast check, and forward it to the other
// operator().
}
};
Suppose I have the following abstract base class:
class Base {
public:
virtual void method() = 0;
virtual const bool operator==(const Base& other) const = 0;
};
And a concrete derived class.
class Derived : public Base {
public:
int value_;
Derived(int value) : value_(value) { }
virtual void method() { }
virtual const bool operator==(const Base& other) const {
const Derived& derived = dynamic_cast<const Derived&>(other);
return operator==(derived);
}
virtual const bool operator==(const Derived& other) const {
return value_ == other.value_;
}
};
Using Google Mock, I now want to assert that a vector defined over the base class contains an example of a concrete class
TEST(ArrayContents, CompareAgainstDerivedClassElements) {
Derived d1(0);
Derived d2(0);
std::vector<Base*> v { &d1 };
ASSERT_THAT(v, Contains( Pointee(d2) ));
}
C++ complains that it cannot create the Eq matcher because Base is an abstract class.
error: no matching function for call to 'Eq'
note: candidate template ignored: substitution failure [with T = perseus::Base]: parameter type 'perseus::Base' is an abstract class
When I change Base so it's not abstract anymore:
class Base {
public:
virtual void method() { }
virtual const bool operator==(const Base& other) const { return false; }
};
C++ throws a std::bad_cast exception at the dynamic_cast expression.
Is such an assertion possible with Google Mock?
Turns out, that the solution is to use the WhenDynamicCastTo matcher:
ASSERT_THAT(v, Contains( WhenDynamicCastTo<Derived*>(Pointee(d2)) ));
This way, I also don't need the virtual operator== methods.
Consider the following abstract class:
class Abstract {
public:
// ...
virtual bool operator==(const Abstract& rhs) const = 0;
// ...
};
Now suppose I'm creating multiple derived classes from this abstract class. However, each one uses a different algorithm when comparing with its own type, and a generic algorithm when comparing with any of the other derived classes. Between the following two options, which would be the better, more efficient option?
Option A:
class Derived : public Abstract {
public:
// ...
bool operator==(const Abstract& rhs) const {
// Code for comparing to any of the other derived classes
}
bool operator==(const Derived& rhs) const {
// Code for comparing to myself
}
// ...
};
Option B:
class Derived : public Abstract {
public:
// ...
bool operator==(const Abstract& rhs) const {
const Derived* tmp = dynamic_cast<const Derived*>(&rhs);
if (tmp) {
// Code for comparing to myself
}
else {
// Code for comparing to any of the other derived class
}
}
};
I'm really curious as to what advantages and disadvantages these options would have, as C++ typecasting is a relatively mysterious topic to me. Furthermore, which solution is more "standard", and does the second solution have any impacts on performance?
Is there possibly a third solution? Especially if there were many derived classes, each needing its own special comparison algorithm against different derived classes?
Your two methods are for different situation. For option A, the static type of rhs is used to decide which function to call, and for option B the dynamic type is used.
So if you want your program to choose its behavior base on the "real" type of the argument, I think you should choose the second option. If types can be known at compile time, option A should be used since it gives better performance.
I think that option B is what you are looking for if you're expecting the == operator to use the dynamic type of the argument. For example:
class base
{
public:
virtual bool operator ==( const base& other ) = 0;
};
class derived : public base
{
public:
bool operator ==( const base& other ) { return false; }
bool operator ==( const derived& other ) { return true; }
};
int main()
{
base* a = new derived;
base* b = new derived;
std::cout << ( *a == *b ) << std::endl;
}
This prints:
0
So operator ==( const base& other ) gets called, even if the actual dynamic type is derived.
You actually can do it third way using one of the techiniques to implement double dispatching. This approach is fully described in Item 31 of "More Effective C++". Here is small example:
#include <iostream>
class Derived1;
class Derived2;
class Base
{
public:
virtual bool operator==( Base& other) = 0;
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived1& other) {return false;}
virtual bool compare( Derived2& other) {return false;}
};
class Derived1 : public Base
{
public:
virtual bool operator==( Base& other) {return other.compare(*this);}
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived1& other) {return true;}
};
class Derived2 : public Base
{
public:
virtual bool operator==( Base& other) {return other.compare(*this);}
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived2& other) {return true;}
};
int main()
{
Base *a = new Derived1;
Base *b = new Derived1;
Base *c = new Derived2;
std::cout << (*a == *b) << std::endl;
std::cout << (*a == *c) << std::endl;
return 0;
}
Output:
1
0
Unfortunately C++ have no multimethods that would choose the current function to call based on dynamic type information. You need double dispatch, visitor pattern or some other trick to implement the behavior.
Suppose I have the following class hierarchy:
class A
{
int foo;
virtual ~A() = 0;
};
A::~A() {}
class B : public A
{
int bar;
};
class C : public A
{
int baz;
};
What's the right way to overload operator== for these classes? If I make them all free functions, then B and C can't leverage A's version without casting. It would also prevent someone from doing a deep comparison having only references to A. If I make them virtual member functions, then a derived version might look like this:
bool B::operator==(const A& rhs) const
{
const B* ptr = dynamic_cast<const B*>(&rhs);
if (ptr != 0) {
return (bar == ptr->bar) && (A::operator==(*this, rhs));
}
else {
return false;
}
}
Again, I still have to cast (and it feels wrong). Is there a preferred way to do this?
Update:
There are only two answers so far, but it looks like the right way is analogous to the assignment operator:
Make non-leaf classes abstract
Protected non-virtual in the non-leaf classes
Public non-virtual in the leaf classes
Any user attempt to compare two objects of different types will not compile because the base function is protected, and the leaf classes can leverage the parent's version to compare that part of the data.
For this sort of hierarchy I would definitely follow the Scott Meyer's Effective C++ advice and avoid having any concrete base classes. You appear to be doing this in any case.
I would implement operator== as a free functions, probably friends, only for the concrete leaf-node class types.
If the base class has to have data members, then I would provide a (probably protected) non-virtual helper function in the base class (isEqual, say) which the derived classes' operator== could use.
E.g.
bool operator==(const B& lhs, const B& rhs)
{
return lhs.isEqual( rhs ) && lhs.bar == rhs.bar;
}
By avoiding having an operator== that works on abstract base classes and keeping compare functions protected, you don't ever get accidentally fallbacks in client code where only the base part of two differently typed objects are compared.
I'm not sure whether I'd implement a virtual compare function with a dynamic_cast, I would be reluctant to do this but if there was a proven need for it I would probably go with a pure virtual function in the base class (not operator==) which was then overriden in the concrete derived classes as something like this, using the operator== for the derived class.
bool B::pubIsEqual( const A& rhs ) const
{
const B* b = dynamic_cast< const B* >( &rhs );
return b != NULL && *this == *b;
}
If you dont want to use casting and also make sure you will not by accident compare instance of B with instance of C then you need to restructure your class hierarchy in a way as Scott Meyers suggests in item 33 of More Effective C++. Actually this item deals with assignment operator, which really makes no sense if used for non related types. In case of compare operation it kind of makes sense to return false when comparing instance of B with C.
Below is sample code which uses RTTI, and does not divide class hierarchy into concreate leafs and abstract base.
The good thing about this sample code is that you will not get std::bad_cast when comparing non related instances (like B with C). Still, the compiler will allow you to do it which might be desired, you could implement in the same manner operator< and use it for sorting a vector of various A, B and C instances.
live
#include <iostream>
#include <string>
#include <typeinfo>
#include <vector>
#include <cassert>
class A {
int val1;
public:
A(int v) : val1(v) {}
protected:
friend bool operator==(const A&, const A&);
virtual bool isEqual(const A& obj) const { return obj.val1 == val1; }
};
bool operator==(const A& lhs, const A& rhs) {
return typeid(lhs) == typeid(rhs) // Allow compare only instances of the same dynamic type
&& lhs.isEqual(rhs); // If types are the same then do the comparision.
}
class B : public A {
int val2;
public:
B(int v) : A(v), val2(v) {}
B(int v, int v2) : A(v2), val2(v) {}
protected:
virtual bool isEqual(const A& obj) const override {
auto v = dynamic_cast<const B&>(obj); // will never throw as isEqual is called only when
// (typeid(lhs) == typeid(rhs)) is true.
return A::isEqual(v) && v.val2 == val2;
}
};
class C : public A {
int val3;
public:
C(int v) : A(v), val3(v) {}
protected:
virtual bool isEqual(const A& obj) const override {
auto v = dynamic_cast<const C&>(obj);
return A::isEqual(v) && v.val3 == val3;
}
};
int main()
{
// Some examples for equality testing
A* p1 = new B(10);
A* p2 = new B(10);
assert(*p1 == *p2);
A* p3 = new B(10, 11);
assert(!(*p1 == *p3));
A* p4 = new B(11);
assert(!(*p1 == *p4));
A* p5 = new C(11);
assert(!(*p4 == *p5));
}
I was having the same problem the other day and I came up with the following solution:
struct A
{
int foo;
A(int prop) : foo(prop) {}
virtual ~A() {}
virtual bool operator==(const A& other) const
{
if (typeid(*this) != typeid(other))
return false;
return foo == other.foo;
}
};
struct B : A
{
int bar;
B(int prop) : A(1), bar(prop) {}
bool operator==(const A& other) const
{
if (!A::operator==(other))
return false;
return bar == static_cast<const B&>(other).bar;
}
};
struct C : A
{
int baz;
C(int prop) : A(1), baz(prop) {}
bool operator==(const A& other) const
{
if (!A::operator==(other))
return false;
return baz == static_cast<const C&>(other).baz;
}
};
The thing I don't like about this is the typeid check. What do you think about it?
If you make the reasonable assumption that the types of both objects must be identical for them to be equal, there's a way to reduce the amount of boiler-plate required in each derived class. This follows Herb Sutter's recommendation to keep virtual methods protected and hidden behind a public interface. The curiously recurring template pattern (CRTP) is used to implement the boilerplate code in the equals method so the derived classes don't need to.
class A
{
public:
bool operator==(const A& a) const
{
return equals(a);
}
protected:
virtual bool equals(const A& a) const = 0;
};
template<class T>
class A_ : public A
{
protected:
virtual bool equals(const A& a) const
{
const T* other = dynamic_cast<const T*>(&a);
return other != nullptr && static_cast<const T&>(*this) == *other;
}
private:
bool operator==(const A_& a) const // force derived classes to implement their own operator==
{
return false;
}
};
class B : public A_<B>
{
public:
B(int i) : id(i) {}
bool operator==(const B& other) const
{
return id == other.id;
}
private:
int id;
};
class C : public A_<C>
{
public:
C(int i) : identity(i) {}
bool operator==(const C& other) const
{
return identity == other.identity;
}
private:
int identity;
};
See a demo at http://ideone.com/SymduV
I think this looks weird:
void foo(const MyClass& lhs, const MyClass& rhs) {
if (lhs == rhs) {
MyClass tmp = rhs;
// is tmp == rhs true?
}
}
If implementing operator== seems like a legit question, consider type erasure (consider type erasure anyways, it's a lovely technique). Here is Sean Parent describing it.
Then you still have to do some multiple-dispatching. It's an unpleasant problem. Here is a talk about it.
Consider using variants instead of hierarchy. They can do this type of things easyly.