我们有我们的项目接口,一个特殊的框架,并要求部分是,它代表一个接口的类只可作为虚基类,不是非虚拟的。 有没有办法在代码执行呢? 如果类是从非虚拟衍生也就是说,产生一个编译错误。
我已经获得C ++ 11如通过2010 VS实现:这意味着static_assert
, enable_if
和<type_traits>
是可用的。
我们有我们的项目接口,一个特殊的框架,并要求部分是,它代表一个接口的类只可作为虚基类,不是非虚拟的。 有没有办法在代码执行呢? 如果类是从非虚拟衍生也就是说,产生一个编译错误。
我已经获得C ++ 11如通过2010 VS实现:这意味着static_assert
, enable_if
和<type_traits>
是可用的。
IMO,没有可用于这个问题不干净,独立于平台的解决方案。
最好的办法就是手动去和每一个继承更改为virtual
继承。
为了实现这个目标,确定你的界面的派生类(比如class Base
)易(!)。 下面的步骤可以为:
class Base
作为final
(C ++ 11); 即class Base final { ...
virtual
final
的关键字并成功编译代码 这个过程(不幸)必须定期其次,当你想要做这样的健全检查。
这是可能的检查在编译时。 最关键的是,如果我们有一个菱形图案:
你可以明确地投D&
给A&
然而,如果继承非虚:
中投会含糊。 所以让我们尝试做一个钻石!
template <typename Base, typename Derived>
class make_diamond {
struct D2 : virtual Base { }; // this one MUST be virtual
// otherwise we'd NEVER have a diamond
public:
struct type : Derived, D2 { };
};
在这一点它只是一个void_t
风格类型的特点:
template <typename Base, typename Derived, typename = void>
struct is_virtual_base_of : std::false_type { };
template <typename Base, typename Derived>
struct is_virtual_base_of<Base, Derived, void_t<
decltype(static_cast<Base&>(
std::declval<typename make_diamond<Base, Derived>::type&>()))
>> : std::true_type { };
如果转换是明确的,在偏特表达将是有效的,而且将专业化是优选的。 如果转换是不明确的,我们将有一个替代故障,并与主告终。 需要注意的是Base
在这里实际上并不需要有任何virtual
成员函数:
struct A { };
struct B : public A { };
struct C : virtual A { };
std::cout << is_virtual_base_of<A, B>::value << std::endl; // 0
std::cout << is_virtual_base_of<A, C>::value << std::endl; // 1
如果有任何纯虚成员函数,我们没有覆盖他们,因为我们从来没有真正构建一个对象。
struct A2 { virtual void foo() = 0; };
struct B2 : public A2 { void foo() override { } };
struct C2 : virtual A2 { void foo() override { } };
std::cout << is_virtual_base_of<A2, B2>::value << std::endl; // 0
std::cout << is_virtual_base_of<A2, C2>::value << std::endl; // 1
当然,如果你的类被标记final
,这将根本无法工作。 不过,如果它是final
,它不会不管它有什么样的继承反正。
有趣的问题。 您可以通过隐藏的接口类和暴露从接口继承几乎一个具体的类去接近你想要什么。 这显然需要一些解决方法和尴尬,但也可能是适应您的需求。 下面是一个例子:
#include <iostream>
using namespace std;
class Hide {
struct VInterface {
void foo() const { cout << "VInterface::foo()\n"; }
VInterface const &as_interface() const { return *this; }
protected:
virtual ~VInterface() { }
};
public:
struct VBase : virtual VInterface {
};
};
typedef Hide::VBase VBase;
struct VDiamond1 : VBase { };
struct VDiamond2 : VBase { };
struct VConcrete : VDiamond1, VDiamond2 { };
int main() {
VConcrete vc;
auto const &vi = vc.as_interface();
vi.foo();
}
它可能会使用重建的名称decltype()
和as_interface()
可能是继承使用,但我试过的那些导致编译器错误的析构函数是受保护的,所以我希望如果可能的话,它至少比较困难,而且可能会为您的需要是足够的。