这段代码如何禁止继承工作?

时间:2011-08-26 15:53:03

标签: c++ inheritance hierarchy access-modifiers

我发现了一些相当奇怪的代码:

class Base {
public:
    virtual bool IsDerived() const { return false; }
};

class Derived : public Base {
public:
    bool IsDerived() const { return true; }
};

Derived* CastToDerived( Base* base )
{
    // private and protected inheritance from Derived is prohibited
    Derived* derived = dynamic_cast<Derived*>(base);
    if( derived == 0 ) {
       assert( !base->IsDerived() );
    }
    return derived;
}

我没有得到关于私人和受保护遗产的文章。

假设,我使用Derived修饰符从<{1}}继承:

protected

会发生什么?如何触发class FurtherDerived : protected Derived { };

4 个答案:

答案 0 :(得分:1)

如果您有ProtectedPrivate继承,则无法执行此操作:

Base *ptr = new Derived();

你也不能这样做,

Derived *ptr1 = new Derived();
Base *ptr = ptr1;

这是因为,BaseDerived

无法访问的基础

由于您不能将Base类指针指向Derived类对象,因此该检查看起来多余。


修改
即使您不能直接将Derived类对象分配给Base类指针,也可以通过以下其他方式实现:如果Derived类的函数返回{{1}类指针。

简而言之,即使派生是BaseBase,A Derived类指针也可能指向protected类对象。

鉴于上述情况,

根据C ++标准:
5.2.7.8:

  

运行时检查按逻辑执行如下:
   - 如果在由v指向(引用)的大多数派生对象中,v指向(引用)T对象的公共基类子对象,并且如果只有一个对象类型T是从指向的子对象派生的(参考)v,结果是指向该T对象的指针(左值引用)    - 否则,如果v指向(引用)最派生对象的公共基类子对象,并且最派生对象的类型具有类型为T的基类,则这是明确的, private,结果是指向最派生对象的 的T子对象的指针(左值引用)。
   - 否则,运行时检查失败。

请注意,该标准明确规定派生要求为公开。
因此,如果推导为publicdynamic_cast并且返回protected(因为您正在使用指针)和{{privateNULL将检测将投射视为不正确的投射。 1}}将被调用。

是的,代码非常有效。它确实做了评论所说的


这个 sample ,证明它符合评论:

assert

答案 1 :(得分:0)

IsDerived是基类中定义的虚函数,函数根据您调用函数的对象的 static 类型进行解析。这意味着,这不是问题。它会工作。 (或许,我错过了你的问题)。

答案 2 :(得分:0)

dynamic_cast执行运行时检查(5.2.7 / 8)。

如果BaseDerived继承为受保护或私有,则运行时检查将失败。

转换为指针时失败的运行时检查值是NULL指针(5.2.7 / 9)。

因此,代码是私有和受保护后代的变通方法:如果您使用Derivedprotected继承privatedynamic_cast将返回NULL并且自定义检查将被执行。

答案 3 :(得分:0)

  

我没有得到关于私人和受保护遗产的文章。

答案很简单。像许多其他评论一样,这个评论是一个没有以任何方式,形状或形式描述代码的评论。

示例:

class PrivateDerived : private Derived {
public:
   Base* cast_to_base () {
      return dynamic_cast<Base*>(this);
   }   
};  

void check_base (const char * id, Base* pbase) {
   if (pbase == 0) {
      std::cout << id << " conversion yields a null pointer.\n";
   }
   else {
      std::cout << id << "->IsDerived() = "
                << pbase->IsDerived() << "\n";
      Derived* pderived = CastToDerived (pbase);
      std::cout << "CastToDerived yields "
                << (pderived ? "non-null" : "null") << " pointer.\n";
      std::cout << "pderived->IsDerived() = "
                << pderived->IsDerived() << "\n\n";
   }
}

int main () {
   PrivateDerived private_derived;

   // Good old c-style cast can convert anything to anything.
   // Maybe a bit disfunctional, but it works in this case.
   check_base ("c_style_cast", (Base*)&private_derived);

   // The cast_to_base method can see the private inheritance,
   // and does so without invoking undefined behavior.
   check_base ("cast_method", private_derived.cast_to_base());

   return 0;
}

使用多个版本的gcc和clang进行测试;他们都没有提出assert陈述。

<强>附录
我怀疑所发生的事情是在一些特定的机器上使用某些特定的编译器,所讨论的代码确实设法做了作者认为它应该做的事情。我怀疑作者从来没有测试过这个假设的支票,看看它是否真的像宣传的那样有效。