防止在C ++中实现虚拟方法
-
23-08-2019 - |
题
我在C ++中有以下类层次结构:
class Base {
virtual void apply() = 0;
};
class Derived : public Base {
virtual void apply() {
// implementation here that uses derived_specialty
}
virtual void derived_specialty() = 0;
};
class Implementation : public Derived {
virtual void derived_specialty() {
// implementation
}
};
我想保证实施级别的课程不会提供自己的应用程序实施,并且他们只能实施derived_specialty。是否有任何方法可以保证从派生中继承的类不会实现应用程序,以便使用派生::应用程序实现?我的理解是,在C ++中,一种在基类中虚拟的方法是虚拟的,直到继承层次结构,但是如果C ++中有任何技巧可以完成,我将有兴趣听到有关它们的消息。
我总是对C ++允许的事情感到惊讶,因此我认为值得一提的是。 :)
解决方案
您可以通过构图做到这一点:
class Base {
virtual void apply();
};
class Derived : public Base {
class IImplementation {
virtual void derived_specialty() = 0;
};
IImplementation& m_implementation;
Derived(IImplementation& implementation)
: m_implementation(implementation)
{}
virtual void apply() {
// implementation here that uses m_implementation.derived_specialty
}
};
class Implementation : Derived::IImplementation {
virtual void derived_specialty() {
// implementation
}
};
其他类仍然可以派生并覆盖应用方法,但是您的实现类不再是这些类别之一。
其他提示
您可以使实施成为代表类,而不是派生的专业化
class Derived : public Base
{
Derived()
void apply()
{
//whatever, delegate to impl class instance
impl->apply_specialization();
}
Impl* impl;
};
class Impl : public WhateverImplInterface
{
void apply_specialization(){}
};
然后,实现无法访问应用功能,并且与层次结构分开。然后,通过IMPH类的实例对派生类进行参数化。
在您的文档中明确限制。
“我想保证实施级别的课程不会提供自己的申请实施。”
你不能。
到目前为止,我所看到的示例都没有阻止任何派生类定义自己的应用功能。他们都提供了建模应用和派生之间关系的方法,向用户暗示他们 不应该 替代申请。但是,您可以在文档线中实现同样的目标。
您正在寻找的是C ++中不存在的Java最终声明,对吗?
您可以使基础::应用非虚拟元素,并在基础内也使用模板方法模式。
本文解释了这种做法的优势:
http://www.gotw.ca/publications/mill18.htm
您可以在攻击方中提出断言以确保 申请 没有被覆盖:
class Base {
virtual void apply() = 0;
};
class Derived : public Base {
virtual void apply() {
// implementation here that uses derived_specialty
}
virtual ~Derived() {
assert(this->apply == Derived::apply);
}
virtual void derived_specialty() = 0;
};
class Implementation : public Derived {
virtual void derived_specialty() {
// implementation
}
};
这里的想法是,> apply将在派生时从虚拟表中获取方法地址,:: apply apply在编译时间内解决了解决方案。如果它们是平等的,则在实施类中不会再次申请。这种方法还具有一个优势,即它在发行版中没有施加性能惩罚,在该版本中,sostert()宏应(应该)从生成的代码中剥离。
总是有访问修饰符:
class base {
protected: virtual void real_apply() = 0;
};
class derived : public base {
void real_apply();
public:
apply() { real_apply(); }
};
class other : public derived {
void func() {
apply(); // this is ok
real_apply(); // this is a compile time error
}
};