我认为我需要的是一个纯虚函数,除了基类 有一个实现,派生类不能默认为(并且此规则必须传播)。与final
相反?
我有一些来自共同基础的类型。 base是一个有用的类型,一些派生类型派生自其他派生类型。我将仅使用对基类的引用,但我需要一个virtual operator==()
来查看这个并调用适合每种情况的手动比较。 operator==()
的一种二维vtable。
实现不会传播到派生类是很重要的,因为不小心让这种情况发生可能会导致不兼容类型之间的比较,这些类型会落到基类实现中,而是兼容类型产生假阳性。
我的意思是让特定的功能等效案例比较相同,尽管它们在不同的类别中表达。我希望问题可以扩展到其他操作,也许我在这里使用operator==()
并不合适。
我没有声称知道C ++ - 我只是一个试图成为惯用语的C hack。
到目前为止,我已经解决了这个问题:
class base;
class foo;
class bar;
class baz;
#define COMPARE public: \
virtual bool equal(base const &p) const; \
virtual bool equal(foo const &p) const; \
virtual bool equal(bar const &p) const; \
virtual bool equal(baz const &p) const; \
virtual bool operator==(base const &p) const { return p.equal(*this); }
class base {
int a_;
public:
base(int a) : a_(a) {}
COMPARE
};
class foo : public base {
int b_;
public:
foo(int a, int b) : base(a), b_(b) {}
COMPARE
};
class bar : public base {
int c_;
public:
bar(int a, int c) : base(a), c_(c) {}
COMPARE
};
class baz : public bar {
int d_;
public:
baz(int a, int c, int d) : bar(a, c), d_(d) {}
COMPARE
};
现在,感谢COMPARE
,必须实现所有T::equal()
,并且不允许其中任何一个都退回到早期的实现。此外,每个类都有自己的operator==()
,它为自己的类型(而不是基类类型)调用适当的equal()
。
我想要的是以COMPARE
现在的方式强制执行这些规则,但不需要记住每个派生类必须引用宏,理想情况下(要成为C ++ - 惯用)而不使用宏观。
正确的C ++方法是什么?
答案 0 :(得分:3)
我还在学习,但你所描述的听起来很像它可能需要双重调度和/或访客模式。
对于双重发送,例如:
class base;
class foo;
class bar;
class baz;
class base {
int a_;
public:
base(int a) : a_(a) {}
virtual bool operator==(const base&) const =0;
virtual bool operator==(const foo&) const =0;
virtual bool operator==(const bar&) const =0;
virtual bool operator==(const baz&) const =0;
};
class foo : public base {
int b_;
public:
foo(int a,int b) : base(a),b_(b) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
class bar : public base {
int c_;
public:
bar(int a,int c) : base(a),c_(c) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
class baz : public bar {
int d_;
public:
baz(int a,int c,int d) : bar(a,c),d_(d) {}
bool operator==(const base&) const override;
bool operator==(const foo&) const override;
bool operator==(const bar&) const override;
bool operator==(const baz&) const override;
};
这看起来很像上面提到的宏选项。 :)
从TC ++ PL第4版,第22.3.1节谈到双重调度,提到或许更确切地说是使用预先计算的查找表。像
这样的东西bool equal(const base& b1,const base& b2)
{
auto i = index(type_id(b1),type_id(b2));
return intersect_tbl[i](b1,b2);
}
答案 1 :(得分:0)
除了基类确实有一个实现,派生类不能默认为(并且此规则必须传播)
如果这是唯一的问题,那么Ben Voigt在评论中提到 - 这不是问题,因为可以实现纯虚函数。
此外,一旦派生类重写,我需要相同的规则, 更多派生类不使用覆盖(如果必须的话) 然后他们总是可以在他们自己的实现中明确地调用它)
如果是这种情况,那么“惯用的C ++方式”可能不会使用继承来模拟“派生” - “进一步派生”。继承通常用于模拟可替代性或模型多态性,但它既不在这里。换句话说:模型“派生” - 由组合“进一步衍生”。
答案 2 :(得分:0)
所以这似乎是强制派生类提供特定函数的自己的实现的一种方法:
template<typename T> struct sweep : public T {
template <class... Args> sweep(Args&&... args) : T(args...) { }
virtual bool equal(base const &p) const = 0;
virtual bool equal(foo const &p) const = 0;
virtual bool equal(bar const &p) const = 0;
virtual bool equal(baz const &p) const = 0;
virtual bool operator==(base const &p) const = 0;
};
class base { ... };
class foo : public sweep<base> {
int b_;
public:
foo(int a, int b) : sweep(a), b_(b) {}
...
};
它仍然需要派生类记住做一些特定的事情来约束自己 - 使用sweep
模板从基类派生 - 但它至少是C ++而不是C。
它还具有以下优点:模板可以刷新默认实现,而不是使它们成为纯虚拟实现;像这样:
template<typename T> struct sweep : public T {
...
virtual bool equal(base const &p) const { return false; }
...
};
基于没有进一步指导的理由,每次比较都应该失败。这实际上更接近我的需要 - 但不是我要求的。