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;
}
Related
I have base class like this:
class Base{
public:
virtual Base *createNew(){
auto newItem = new Base();
setNew(newItem);
return newItem;
};
void setNew(Base *item){
item->value = value;
};
private:
int value;
};
A number of derived classes are shown below, each of which has a createNew interface that returns a derived object.
class Derive1 : public Base{
Derive1 *createNew(){
auto newItem = new Derive1();
setNew(newItem);
return newItem;
};
void setNew(Derive1 *item){
Base::setNew(item);
item->value1 = value1;
};
private:
int value1;
};
class Derive2 : public Base{
Derive2 *createNew(){
auto newItem = new Derive2();
setNew(newItem);
return newItem;
};
void setNew(Derive2 *item){
Base::setNew(item);
item->value2 = value2;
};
private:
int value2;
};
class Derive3 : public Base{
Derive3 *createNew(){
auto newItem = new Derive3();
setNew(newItem);
return newItem;
};
void setNew(Derive3 *item){
Base::setNew(item);
item->value3 = value3;
};
private:
int value3;
};
int main(int argc, char *argv[])
{
std::list<Base *> list;
list.push_back(new Derive1);
list.push_back(new Derive2);
list.push_back(new Derive3);
list.push_back(new Derive2);
list.push_back(new Derive1);
std::list<Base *> listNew;
for(auto item : list)
{
listNew.push_back(item->createNew());
}
...
//ignore the memory leak.
}
Is there any easy way to not write every createNew in the derived class, because they are similar, the only difference is the type. Do templates help?
Supposedly you want to use the Curiously Recurring Template Pattern (CRTP) for this. Here is an example where we introduce template class BaseT that inherits from Base. Note how each derived class inherits from BaseT passing itself as template parameter.
class Base {
public:
virtual Base* createNew() = 0;
virtual ~Base() {}
};
template <typename T>
class BaseT : public Base {
public:
Base* createNew() override {
return createDerived();
}
T* createDerived() {
auto newItem = new T();
setNew(newItem);
return newItem;
};
void setNew(T* item){
item->value = value;
setNewDerived(item);
};
virtual void setNewDerived(T* item) {}
virtual ~BaseT() {}
private:
int value;
};
class Derive1 : public BaseT<Derive1> {
public:
void setNewDerived(Derive1* item) override {
item->value1 = value1;
}
private:
int value1;
};
class Derive2 : public BaseT<Derive2> {
public:
void setNewDerived(Derive2 *item) override {
item->value2 = value2;
}
private:
int value2;
};
class Derive3 : public BaseT<Derive3> {
public:
void setNewDerived(Derive3 *item) override {
item->value3 = value3;
};
private:
int value3;
};
Is this what you are trying to do?
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 Base class with several derived classes:
class Base {
private:
long id;
public:
Base() {}
~Base() {}
Base &operator = (long temp) {
id = temp;
return *this;
}
};
template <class C>
class Temp1 : public Base {
public:
Temp1() {}
~Temp1() {}
//do something;
};
template <class C>
class Temp2 : public Base {
public:
Temp2() {}
~ Temp2() {}
//do something;
};
class Executor1 : public Temp1<int> {
public:
Executor1() {}
~Executor1() {}
};
class Executor2 : public Temp2<char> {
public:
Executor2() {}
~Executor2() {}
};
I want those classes to support operator =.
e.g:
int main()
{
long id1 = 0x00001111, id2 = 0x00002222;
Executor1 exec1;
Executor2 exec2;
exec1 = id1; //exec2.id = id1;
exec2 = id2; //exec2.id = id2;
}
I define operator = in Base whose declaration is Base &operator = (long);.
But there is a problem clearly that = doesn't work to derive classes. So I have to define operator = totally do the same thing to every Executor.
How to deal with this case in Base in a better way?
You have to pull the =-operator into the scope of the class:
class Base
{
public:
long id;
Base& operator=(long id)
{
this->id = id;
return *this;
}
};
class Temp2
: public Base
{
public:
using Base::operator=;
};
You have to pull the operator= into the scope because the implicitly generated copy operator= of Temp2 was hiding the operator= of Base. Got this hint from #Angew from's comment.
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:
c++ Function to return an enum?
(4 answers)
Closed 7 years ago.
i am having trouble with the following:
i need to use enum to enumerate 4 inherited classes (at this point they have no difference between them other the the enum) and then return the type via a virtual function called "whoAmI", i don't understand the syntax as to how i would do the return part
the following is the relevant code;
in class.h
virtual void whoAmI();
enum gettype { easyTile, cropTile, waterTile, mediumTile};
in class.cpp
void tile::whoAmI()
{
}
You can change the return type of your function to the name of your enum, then use = 0 to declare the base class is pure virtual.
class ITile
{
public:
enum class EType { easy, crop, water, medium };
virtual EType whoAmI() const = 0;
};
Then the derived classes can override this method to return the correct enum type, for example
class EasyTile : public ITile
{
public:
EasyTile() = default;
EType whoAmI() const override { return EType::easy; }
};
class CropTile : public ITile
{
public:
CropTile() = default;
EType whoAmI() const override { return EType::crop; }
};
So as an example (live demo)
int main()
{
std::vector<std::unique_ptr<ITile>> tiles;
tiles.emplace_back(new EasyTile);
tiles.emplace_back(new CropTile);
for (auto const& tile : tiles)
{
std::cout << static_cast<int>(tile->whoAmI()) << std::endl;
}
}
Will output
0
1
You can easily do it like that:
class TileBase
{
public:
enum Type { easyTile, cropTile, waterTile, mediumTile };
virtual Type whoAmI() const = 0;
virtual ~TileBase() = default;
};
class EasyTile : public TileBase
{
Type whoAmI() const override { return easyTile; }
};
You see, you need to specify the enum Type as return type instead of void.
#include <iostream>
using namespace std;
class Tile{
public:
enum getType { easyTile, cropTile, waterTile, mediumTile};
virtual getType whoAmI(){}
};
class easyTile:public Tile{
public:
getType whoAmI(){return getType::easyTile;}
};
class cropTile: public Tile{
public:
virtual getType whoAmI(){return getType::cropTile;}
};
class waterTile: public Tile{
public:
virtual getType whoAmI(){return getType::waterTile;}
};
class mediumTile: public Tile{
public:
virtual getType whoAmI(){ return getType::mediumTile;}
};
int main() {
Tile *T = new cropTile;
cout << T->whoAmI() << endl;
delete T;
return 0;
}
Output : 1