#include <iostream>
using namespace std;

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

const char * TF(bool b)
{
	return b ? "True" : "False";
}

int main() {
	B b1(1);
	B b2(2);
	C c1(1);
	C c2(1);
	A& a1 = b1;
	A& a2 = b2;
	A& a3 = c1;
	A& a4 = c2;
	cout << "a1 == b1: " << TF(a1 == b1) << endl;
	cout << "a1 == a2: " << TF(a1 == a2) << endl;
	cout << "a2 == a3: " << TF(a2 == a3) << endl;
	cout << "a3 == a4: " << TF(a3 == a4) << endl;
	
	// your code goes here
	return 0;
}