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;
};
Related
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!
I have a parent class Obj with empty virtual function cmp
class Obj{
public:
virtual int cmp(const Obj& val) = 0;
...
};
I am trying to define that function in the subclass MyString, but instead of const Obj& as argument, i use const MyString& which probably occures the error "Emprty virtual function Obj::cmp has no redifinition"
class MyString : public Obj{
private:
...
public:
virtual int cmp(const MyString& val){
... using private values of MyString
}
};
So how can i solve that, if i have 3-4 subclasses which uses their own variables in that function
An example that comes to my mind is the curiously recurring template pattern. It goes like this:
#include <iostream>
#include <ostream>
template <typename T>
struct Base
{
virtual int cmp(T const &) = 0;
};
struct First : Base<First>
{
virtual int cmp(First const &);
};
int First::cmp(First const &)
{
std::cout << "First\n";
return 1;
}
struct Second : Base<Second>
{
virtual int cmp(Second const &);
};
int Second::cmp(Second const &)
{
std::cout << "Second\n";
return 2;
}
int main()
{
Base<First>* f1 = new First();
Base<First>* f2 = new First();
Base<Second>* s = new Second();
f1->cmp(*dynamic_cast<First*>(f2)); // if this will throw, use RAII instead of deletes below
// f1->cmp(*dynamic_cast<Second*>(f2)); error: cannot convert Second to First
delete f1;
delete f2;
}
If you want to use overriding you have to define method in subclasses as it is in base class and can't change parameters of virtual function. In method of subclass you can cast to a type you need.
class Obj
{
public:
virtual int cmp(const Obj& val) = 0;
...
};
class MyString : public Obj
{
private:
...
public:
int cmp(const Obj& val)
{
// cast val to MyString& (you can use dynamic_cast)
... using private values of MyString
}
};
Also you can use overloading. In this case you don't need virtual method in base class.
class Obj
{
public:
int cmp(const Obj& val)
{
// implementation for Obj
}
...
};
class MyString : public Obj
{
private:
...
public:
int cmp(const MyString& val)
{
... using private values of MyString
}
};
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);
}
};
This question already has answers here:
Why does an overridden function in the derived class hide other overloads of the base class?
(4 answers)
Closed 7 years ago.
When compiling the following code :
class Base {
public:
Base(){}
virtual ~Base(){}
virtual bool equals(const Base* rhs) const { return false;}
};
class DerivedA : public Base {
public:
DerivedA() : Base(), val(0) {}
virtual ~DerivedA() {}
virtual bool equals(const DerivedA* rhs) const { return this->val == rhs->val;}
int val;
};
class DerivedB : public Base {
public:
DerivedB() : Base(), val(0) {}
virtual ~DerivedB() {}
virtual bool equals(const DerivedB* rhs) const { return this->val == rhs->val;}
int val;
};
int main() {
const DerivedA a;
const DerivedB b;
std::cout << a.equals(&b);
}
I get:
../main.cpp:104:26: error: no matching function for call to ‘DerivedA::equals(const DerivedB*) const’
std::cout << a.equals(&b);
^
../main.cpp:104:26: note: candidate is:
../main.cpp:88:15: note: virtual bool DerivedA::equals(const DerivedA*) const
virtual bool equals(const DerivedA* rhs) const { return this->val == rhs->val;}
^
../main.cpp:88:15: note: no known conversion for argument 1 from ‘const DerivedB*’ to ‘const DerivedA*’
But why doesn't it use the base class virtual bool equals(const Base* rhs) const?
bool DerivedA::equals(const DerivedA* rhs) const
is not an override of
bool Base::equals(const Base* rhs) const
but an other overload (as you may notice with override) which hides the base method.
If you just want to 'unhide' base method, you may add
using Base::equals;
into your derived class.
But to really solve your issue, you have to use multiple dispatch.
i am a new programer in c++
and i have an abstract class A, and i implemented operators in it.
and now i have two classes B and C that extend A.
for some reason the compiler does not identify the operators.
is it because that operators are not inherrited? or is it because that i have a code bug?
here is the code:
#ifndef A_
#define A_
class A{
public:
friend bool operator==(const A &a1,const A &a2);
}
#endif
inline bool operator==(const A& a1, const A& a2){
....
}
is it not meant to work on B==C and B==B and C==C?
thanx
Matt
The program compiles and runs as expected, correctly calling the right operator when I try it:
class A {
public:
friend bool operator==(const A &a1, const A &a2);
};
bool operator==(const A &a1, const A &a2) {
return false;
}
class B : public A {};
class C : public A {};
int main()
{
B b;
C c;
bool equals = b == c;
return 0;
}
Put the operator inside the class.
#ifndef A_
#define A_
class A
{
...
public:
bool operator==(const A &other)
{
// your operator logic
}
}
#endif
Optionally, you could make it virtual thus allowing you to override it in the derived classes.
My suggestion: don't overload comparison operators in base classes, but implement equivalent protected methods. This will prevent some hard to detect failures in your program.
Example:
class Base
{
protected:
bool equal_base(const Base& other) const
{ return member == other.member;}
private:
unsigned int member;
};
class B_Child : public Base
{
public:
bool operator==(const B_Child& other) const
{ return (member_b == other_member_b) && equal_base(other);}
private:
std::string member_b;
};
class C_Child : public Base
{
public:
bool operator==(const C_Child& other) const
{ return (member_c == other_member_c) && equal_base(other);}
private:
double member_c;
};
Also search the web for "C++ virtual equality operator".
How about:
class A
{
public:
bool operator==(A const& rhs) const
{
return this->isEqual(rhs);
}
private:
virtual bool isEqual(A const& rhS)
{
return /* Your test here */
}
};
class B: public A
{
private:
virtual bool isEqual(A const& rhS)
{
B& theRealRHS = dynamic_cast<B const&>(rhs); // Throws if it is not a B
return /* Your test here */
}
};