Reputation: 1158
Let's say I have a base abstract class B
and a hundred classes which derive from it D1
... D100
. I also have two (smart) pointers unique_ptr<B> p1, p2;
which point to two different instances of types Di
and Dj
. I want to know whether the objects they're pointing to have the same type (i.e. whether i
equals j
). Is there a simple way to do that?
Upvotes: 4
Views: 2506
Reputation: 7915
This may seem a little convoluted at first but it can ensure the operability of what you are looking for in the terms of comparisons. There is a little more overhead to this approach in maintainability, but it will ensure proper comparison without too much overhead of execution in regards of time execution.
#include <string>
#include <iostream>
#include <memory>
class AbstractBase {
public:
enum DerivedTypes {
DERIVED_A,
DERIVED_B
};
protected:
DerivedTypes type_;
public:
explicit AbstractBase( const DerivedTypes type ) : type_( type ) {}
virtual void print() = 0;
DerivedTypes getType() const {
return type_;
}
bool operator==( const AbstractBase& other ) {
return this->type_ == other.getType();
}
};
class DerivedA : public AbstractBase {
public:
const int x = 5;
public:
explicit DerivedA( const DerivedTypes type = DerivedTypes::DERIVED_A ) : AbstractBase( type ) {}
virtual void print() override {
std::cout << "DerivedA\n";
}
};
class DerivedB : public AbstractBase {
public:
const float y = 1.5f;
public:
explicit DerivedB( const DerivedTypes type = DerivedTypes::DERIVED_B ) : AbstractBase( type ) {}
virtual void print() override {
std::cout << "DerivedB\n";
}
};
int main() {
std::unique_ptr<DerivedA> p1 = std::make_unique<DerivedA>( DerivedA() );
std::unique_ptr<DerivedB> p2 = std::make_unique<DerivedB>( DerivedB() );
p1->print();
p2->print();
if ( *p1 == *p2 ) {
std::cout << "pointers are the same\n";
} else {
std::cout << "pointers are not the same\n";
}
std::unique_ptr<DerivedA> p3 = std::make_unique<DerivedA>( DerivedA() );
std::unique_ptr<DerivedA> p4 = std::make_unique<DerivedA>( DerivedA() );
p3->print();
p4->print();
if ( *p3 == *p4 ) {
std::cout << "pointers are the same\n";
} else {
std::cout << "pointers are not the same\n";
}
return 0;
}
The added cost here of the maintainability depends on how many derived classes there are. If this design pattern is used from the beginning it is quite easy to follow. If one has to modify a numerable amount of classes it will take some time and effort to modify the existing code base.
The idea here is that the abstract base class keeps an internal variable of the derived type, has a getter for it's derived type & an overloaded == comparison operator that compares the types. The constructor is forced to take its enumerated type as well as all the derived types. I also defaulted the derived types so that it doesn't have to be passed to their constructors every time a class object is instantiated. This is the overhead of the maintainability.
The simplicity of this comes into play when comparing pointers - smart pointers of multiple derived types. When you look at the main function above you can see that it was simple enough to dereference the smart pointers and the base class's overloaded == operator takes care of business.
If one does need to use the operator==()
to actually compare numerical differences between classes then this can be modified to use a public method in the base class that compares the types and returns a bool instead of the overloaded operator.
Upvotes: 0
Reputation: 138171
Checking C++ RTTI is relatively expensive and cumbersome: consider adding an event tag in the base class, and checking for that value.
enum class EventTag {
A, B
};
struct EventBase {
const EventTag tag;
EventBase(EventTag tag) : tag(tag) {
}
};
struct EventA : public EventBase {
EventA() : EventBase(EventTag::A) {
}
};
struct EventB : public EventBase {
EventB() : EventBase(EventTag::B) {
}
};
if (thisEvent->tag == thatEvent->tag) {
// stuff
}
A union instead of a class hierarchy could also do it for you.
Upvotes: 5
Reputation: 4078
You can use a RTTI typeid, but generally, it is a bad design to must have to use dynamic_cast because it may violate the liskov substitution principle
std::unique_ptr<B> p1, p2;
if(typeid(*p1) == typeid(*p2)) // correction by Justin
Or something like that using name
or hash_code
Upvotes: 7