Overloading == and != operators in C++ with polymorphism - c++

Here is the thing. I have one base class and 4 child classes.
class Base{
public:
virtual int getType() const = 0;
};
class Type1 : public Base{
public:
virtual int getType() const {
return 1;
};
};
class Type2 : public Base{
public:
virtual int getType() const {
return 2;
};
};
class Type3 : public Base{
public:
virtual int getType() const {
return 3;
};
};
class Type4 : public Base{
public:
virtual int getType() const {
return 4;
};
};
I need to overload the == and != operators which do the same thing for all child classes, just retrieve the type values and compare them. So I would naturally implement the operator in the Base class with references to Base as both operands but when I do that, my IDE starts screaming when I use the operators on child views, that it cannot compare structs.
So the question is. Is there a way I can implement the operators just once without having to specify them for each combination of child classes ?
Thanks!

I do not have any problem with this operator:
bool operator==(Base const& x, Base const& y)
{
return x.getType() == y.getType();
}
unless with an accessibility issue: Your getType function is private. If you do not provide any access modifier with classes, all members, variables and functions, are implicitly private.
So you either need a friend declaration or make the getType function public.

class Base {
public:
virtual int getType() const = 0;
bool operator ==(const Base &b) const {
return getType() == b.getType();
}
};
class Type1 : public Base {
public:
virtual int getType() const {
cout << "Type1.getType()" << endl;
return 1;
};
};
class Type2 : public Base {
public:
virtual int getType() const {
cout << "Type2.getType()" << endl;
return 2;
};
};
Usage:
Base *t1 = new Type1(), *t2 = new Type2();
bool res1 = *t1 == *t1; // true, calls Type1.getType() twice
bool res2 = *t1 == *t2; // false, calls Type1.getType() and Type2.getType()

Yes, you can do it in your Base class. There will be no error for doing this.
class Base{
public:
virtual int getType() const = 0;
bool operator==(const Base& rhs) const{
return getType() == rhs.getType();
}
bool operator!=(const Base& rhs) const{
return !(*this == rhs);
}
};

Related

Virtual Equal Function between templated classes (C++)

This question is a follow up on Here. The goal was to implement a virtual equal operator between non templated classes. In this question, I am asking for the same goal for a templated class.
#define EQUAL_FOR_BASE(derived) virtual bool equal(const derived& eq) const { return false; };
#define EQUAL_FOR_DERIVED(this_derived) bool equal(const Equalable& equalable) const { return equalable.equal(*this_derived); };
class RandomClass; //This is for clarification purposes, not used.
class DerivedTemplateType_One;
class DerivedTemplateType_Two;
class Equalable
{
public:
Equalable() = default;
virtual ~Equalable() = default;
virtual bool operator==(const Equalable& eq) { return this->equal(eq); };
EQUAL_FOR_BASE(RandomClass);
EQUAL_FOR_BASE(DerivedTemplateType_One);
EQUAL_FOR_BASE(DerivedTemplateType_Two);
virtual bool equal(const Equalable& eq) const = 0;
};
class RandomClass : public Equalable
{
public:
RandomClass() = default;
~RandomClass() = default;
EQUAL_FOR_DERIVED(this);
virtual bool equal(const RandomClass& rc) const { return m_double == rc.m_double; };
double m_double;
};
class TemplateType : public Equalable //Still pure virtual due to equal in Equalable.
{
public:
TemplateType() = default;
virtual ~TemplateType() = default;
int m_string;
};
class DerivedTemplateType_One : public TemplateType
{
public:
EQUAL_FOR_DERIVED(this);
virtual bool equal(const DerivedTemplateType_One& one) const { return m_int == one.m_int; };
int m_int;
};
class DerivedTemplateType_Two : public TemplateType
{
public:
EQUAL_FOR_DERIVED(this);
virtual bool equal(const DerivedTemplateType_Two& two) const { return m_size == two.m_size; };
std::size_t m_size;
};
template<typename T>
class Target : Equalable
{
public:
T m_t;
};
Q1: I want to limit the template typename T above to be a derived class of TemplateType (derived from Equalable) e.g. Can be DerivedTemplateType_One/Two (Of course there will be Three, Four..)? Isn't there static_assert or some metaprogramming to check this at compile time or would:
template<TemplateType DerivedTypeOneOrTwo>
class Target : public Equalable
{
public:
DerivedTypeOneOrTwo m_t;
};
Work?
Q2: How can I implement the equal operator as I did for RandomClass please?
Q3: I am asking about Q1 in order to limit template types possible so that Q2 is possible, can I generalize Q1: Limit template typename T to classes inheriting from Equalable (instead of TemplateType ) and still do Q2?
Sorry this is getting a bit complicated but there is no easy way :) Thanks very much!!
Ps: I am making everything public to save space, please ignore.
I ended using CRTP if anyone is interested (Please let me know if I am doing something wrong I missed)
template<class Derived>
class Equalable
{
public:
using derived_type = Derived;
bool operator==(const Derived& derived) const { return this->equal(derived); };
bool operator!=(const Derived& derived) const { return !(*this == derived); }
private:
virtual bool equal(const Derived& derived) const = 0;
};
class B : public Equalable<B>
{
public:
B(double d) : m_example(d) {};
private:
virtual bool equal(const B& derived) const override { return derived.m_example == m_example; };
double m_example;
};
class A : public Equalable<A>
{
public:
A(std::string d) : m_example(d) {};
private:
virtual bool equal(const A& derived) const override { return derived.m_example == m_example; };
std::string m_example;
};
Now we can compare element of same type:
int main()
{
A a("string");
B b(1);
A aa("other_string");
B bb(11);
std::cout << (a == aa) << std::endl; //Ok
std::cout << (b == bb) << std::endl; //Ok
std::cout << (a == b) << std::endl; //Wrong, not supported.
};
I tried doing this:
template<class A, class B>
static bool equal(const Equalable<A>& a, const Equalable<B>& b)
{
if (!std::is_same<A, B>::value)
return false;
return a == b;
};
But didn't compile, so I just used equality between same types.
To limit template (As of Question Q1) there a standard check:
static_assert(std::is_base_of<Base, Derived>::value, "Only from Base");
Hope you have better suggestions, I still don't like this :) Thanks everyone!

Why is class abstract although it shouldn't be?

I've been looking at this code for few hours and I can't find why I can't instantiate class. So I have interfaces:
class ICloneable {
public:
virtual ICloneable* clone() const = 0;
virtual ~ICloneable() = 0 {}
};
class IPrintable
{
protected:
virtual void print(std::ostream&) const = 0;
public:
virtual ~IPrintable() = 0;
friend std::ostream& operator<<(std::ostream, const IPrintable&);
};
std::ostream& operator<<(std::ostream os, const IPrintable& other) {
other.print(os);
return os;
}
class IComparable {
protected:
virtual bool is_greater(const IComparable& other) const = 0;
virtual bool is_equal(const IComparable& other) const = 0;
public:
virtual ~IComparable() = 0;
virtual bool operator>(const IComparable& other) const {
return is_greater(other);
}
virtual bool operator<(const IComparable& other) const {
return !(is_greater(other) || is_equal(other));
}
virtual bool operator==(const IComparable& other) const {
return is_equal(other);
}
virtual bool operator!=(const IComparable& other) const {
return !(is_equal(other));
}
};
And I have two classes that inherit these interfaces:
class I2DShape : public IComparable, public IPrintable {
public:
virtual void print(std::ostream& os) const override final {
os << "Circumference: " << this->circumference();
}
virtual bool is_greater(const I2DShape& other) const final {
return this->circumference() > other.circumference();
}
virtual bool is_equal(const I2DShape& other) const final {
return this->circumference() == other.circumference();
}
virtual double circumference() const = 0;
virtual ~I2DShape();
};
class IPositionable : public IPrintable, public IComparable {
public:
virtual void print(std::ostream& os) const override final {
}
virtual bool is_greater(const IPositionable& other) const final {
distance_from_origin() > other.distance_from_origin();
}
virtual bool is_equal(const IPositionable& other) const final {
distance_from_origin() == other.distance_from_origin();
}
virtual double distance_from_origin() const {
return sqrt(pow(center().get_x(), 2) + pow(center().get_y(), 2));
}
virtual Point center() const = 0;
virtual ~IPositionable();
};
And in the final these two classes are inherited by one which represents shape:
class Shape2D : public IPositionable, public I2DShape, public ICloneable {
protected:
int num_of_points;
Point* points;
public:
Shape2D() : num_of_points(0), points(nullptr) {}
Shape2D(int num) : num_of_points(num), points(new Point[num]) {}
Shape2D(const Shape2D& other) : num_of_points(other.num_of_points) {
points = new Point[num_of_points];
for (int i = 0; i < num_of_points; i++) {
points[i] = other.points[i];
}
}
Shape2D& operator=(const I2DShape& other) {
}
virtual Shape2D* clone() const override = 0;
virtual ~Shape2D() {
if(points)
delete[] points;
}
};
When I derive Square from Shape2D and make function for cloning, I get error that it's abstract class:
class Square : public Shape2D {
private:
double side;
public:
Square() {}
Square(double s, Point center) : side(s), Shape2D(1) { points[0] = center;}
virtual Point center() const override{
return points[0];
}
virtual double circumference() const override {
return 4 * side;
}
virtual Square* clone() const override final {
return new Square(*this); //error on this line
}
};
Error: object of abstract class type "Square" is not allowed
Since in interfaces you declared destructors with = 0 you are forcing explicit implementation of it in sub-classes which can be instantiated.
There are two ways to fix it.
Make interface classes in standard way with default destructors (no = 0), using {} or = default.
Add explicit destructor for Square
Note that pure virtual destructor with implementation is treated by gcc and clang as an error.
Related SO questions:
Why do we need a pure virtual destructor in C++?
Pure virtual function with implementation
The error was as #HolyBlackCat stated in the comments, with function is_greater and is_equal because they have different parameters when overriden. Simple fix to this was to remove = 0 from those two functions in IComparable so they weren't pure.

How to compare using base class in derived class data

I have base class and derived class in C++.
I want to determine if the data of the derived class is the same using the pointers of the base class.
enum type
enum class FruitType: int{
Apple,
Orange,
};
base class
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
};
derived class
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
};
initialize
// initialize
std::vector<Base*> fruit_list_ = {
new Apple(42),
new Orange(0.f),
new Apple(1) };
Is there any way to check with HasSameData()?
Base* HasSameData(const Base* pCompare){
for (const auto& list : fruit_list_)
{
if( pCompare->fruit_type == list->fruit_type ){
// how to check same data...?
if( /* ... */ ){
return list;
}
}
}
return nullptr;
}
int main(){
// check same data
Base* pCompare = fruit_list_[2];
if(HasSameData(pCompare)){
// I want to return fruit_list_[2] pointer...
}
}
You could add an abstract method sameData() to the base case
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool sameData(const Base& other) const = 0;
};
Override in the derived classes:
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
virtual bool sameData(const Base& other) const {
const Apple* apple = dynamic_cast<const Apple*>(&other);
return apple && apple->foo == foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
virtual bool sameData(const Base& other) const {
const Orange* orange = dynamic_cast<const Orange*>(&other);
return orange && orange->bar == bar;
}
};
And use it as follows:
// how to check same data...?
if( pCompare->sameData(*list) ){
The simplest way is to use a virtual function to compare equality and implement the comparison logic in the body of the virtual function.
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool Equals(Base *other) const = 0;
};
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Apple)
return false;
return foo == ((Apple*)other)->foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Orange)
return false;
return bar == ((Orange*)other)->bar;
}
};
Then write your comparison function like this:
bool HasSameData(const Base* pCompare){
for (const Base *fruit : fruit_list_)
if (pCompare->Equals(fruit))
return true;
return false;
}

Inheriting and overriding virtual assignment == operator

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;
};

How to have virtual functions that returns different types based on the class to which it belongs without including dummy implementation in Base?

I need a class hierarchy in which the derived classes will have implementation of a virtual function that differs in the return type. How can i do it. What i have tried is the following code:
using namespace std;
class Base
{
public:
Base()
{
cout<<"Constructor of Base"<<endl;
}
virtual Base& Decode()=0;
virtual operator int(){return -1;}
virtual operator string(){return "WRONG";}
};
class Der1:public Base
{
int i;
public:
Der1(int j=0):Base(),i(j)
{
cout<<"COnstructor of Der1"<<endl;
}
Base& Decode()
{
cout<<"Decode in Der1"<<endl;
return *this;
}
operator int()
{
return i;
}
};
class Der2:public Base
{
string s;
public:
Der2(string temp="sajas"):Base(),s(temp)
{
cout<<"Constructor of Der2"<<endl;
}
Base& Decode()
{
cout<<"Decode in Der2"<<endl;
return *this;
}
operator string()
{
return s;
}
};
int main()
{
Base *p=new Der1();
int val=p->Decode();
}
I was thinking if it could work this way user would just have to equate the object to a valid variable. Is there any way to do it without including all the conversion operators in Base with some dummy implementatin?
I guess there is one problem, if it is a Pure virtual function you cannot create an object of the class base. But on the other hand to solve your problem you can try out using templates, something like below.
#include <iostream>
class Base{
public:
Base(){}
virtual ~Base(){}
virtual void show() const {
std::cout << "Base::show()!" << std::endl;
}
};
class A:public Base{
public:
A(){}
virtual ~A(){}
virtual void show() const{
std::cout << "A::show()!" << std::endl;
}
};
template<typename T>
class Factory{
public:
const T* operator()() const{
return &t;
}
private:
T t;
};
int main(){
const A* pA = Factory<A>()();
pA->show();
Factory<A>()()->show();
return 0;
}