在基类与派生类中覆盖具有不同访问权限的方法有什么问题



PC Lint在派生类中重写方法时会发出警告,该派生类的访问说明符不是继承的访问说明符。例如

class B {
public:
virtual void fubar(void);
};
class D : public B {
private:
virtual void fubar(void);
};

我看到的一个解释是,上面的内容违反了Liskov替换原则,但这是派生类具有更严格访问权限的唯一情况(就像上面的例子一样(,对吧?我还注意到,这里有一个通往D::fubar的后门,因为我们可以将一个指向D的引用/指针强制转换为指向B的引用/指示器,然后我们可以调用D::fubar,因为它是虚拟的。还有其他问题吗?

如果派生类的访问权限较宽松,该怎么办?例如:

class B {
protected:
virtual void fubar(void);
};
class D : public B {
public:
virtual void fubar(void);
};

是否存在与这种类型的覆盖相关的任何问题?

更改访问类型本身没有什么问题。语言允许。只是更改它很可能是一个错误,因为基类设计器已经决定了该方法应该具有什么访问权限。

如果你让它更严格,那真的没关系,因为任何指向基类的指针都可以调用它,所以这个几乎总是一个错误。

如果你不那么严格,它可能会暴露出设计问题,所以这也应该被认为是一个可能的错误。

一个可能的用例是,如果您不拥有基类(即,它是一个外部库或其他什么(。您可以使用它来直接公开某些功能,但同样,应该谨慎对待。

关于您的";后门;请注意,访问说明符是指"访问";正确的";使用语言和诊断错误,而不是恶意使用。有一些想法是,总是把受保护的方法当作公共的(甚至根本不使用受保护的(,因为它们可以随时发布。。。。

最后,请注意,覆盖与访问类型无关。您可以执行以下操作,它将按预期工作:

struct Base {
private:
virtual void foo() = 0;
};
struct Derived: public Base {
private:
void foo() override;
};

编译器资源管理器

在这个代码段中,只有Base函数可以调用foo(),但它们将调用Derived中的overriden函数。注意,由于是私有的,派生实现不能调用Base::foo(),因此它是一种通常与纯虚拟函数一起使用的模式。

最新更新