0
我有下面这样简单的例子来说明我想要做的事情。我有一个抽象类A
,它通过两种方法向世界公开了一个公共接口:operator==
和performTasksSpecificToA
。您可以看到我正在使用“模板方法模式”以及“奇怪的循环模板模式”,以确保A
的用户不需要担心A
的执行,换句话说就是AImpl
,而仍然能够检查对两个AImpl
两个实例的平等。有关此方法的更多信息和上下文,请参阅this answer on SO。如何定义一个父类来减少代码重复,同时使用具有相等运算符定义的抽象类?
现在,假设我希望定义一个类B
如下:
class B
{
public:
virtual ~B() = 0;
bool operator(const B& b) const;
void performTasksSpecificToB();
};
正如你可以看到在界定公共operator==
用于比较的子类而言,类B
股同样的问题A
。我如何定义父级,我们称之为Letter
,以避免在A
和B
之间重复代码?
这是我的'简单的例子',它编译和运行。
#include <iostream>
class A
{
public:
virtual ~A() = 0;
bool operator==(const A& a) const;
void performTasksSpecificToA();
private:
virtual bool checkEquality_(const A& a) const = 0;
};
template <class T>
class A_ : public A
{
protected:
bool checkEquality_(const A& a) const override;
private:
virtual bool checkEquality(const T& t) const = 0;
};
class AImpl : public A_<AImpl>
{
public:
AImpl(int val) : val(val){};
bool checkEquality(const AImpl& anAImpl) const override;
private:
int val;
};
A::~A(){}
bool A::operator==(const A& a) const{
return checkEquality_(a);
}
template <class T>
bool A_<T>::checkEquality_(const A& a) const{
const T* other = dynamic_cast<const T*>(&a);
if (other != nullptr){
const T& me = static_cast<const T&>(*this);
return other->checkEquality(me);
}
return false;
}
bool AImpl::checkEquality(const AImpl& anAImpl) const{
return val == anAImpl.val;
}
int main(){
// factory:
AImpl* aImpl1 = new AImpl(1);
AImpl* aImpl2 = new AImpl(2);
AImpl* aImpl3 = new AImpl(1);
// client:
A& A1 = *aImpl1;
A& A2 = *aImpl2;
A& A3 = *aImpl3;
std::cout << "A1 == A2 -> ";
std::cout << (A1 == A2 ? "true" : "false");
std::cout << std::endl;
std::cout << "A1 == A3 -> ";
std::cout << (A1 == A3 ? "true" : "false");
std::cout << std::endl;
delete aImpl1;
delete aImpl2;
delete aImpl3;
return 0;
}
为什么在平等比较中有这么多层次的间接性? –
第一级是为了避免使'A'成为模板类:因此,我将实际的逻辑移到了'A_'。第二个层次,即使用'A :: checkEquality_'是为了区分'A'公开曝光的方法和需要被子分类占据的部分(根据'模板方法模式')。 – wesanyer