禁止继承的代码是如何工作的

How does this code to forbid inheritance work?

本文关键字:工作 何工作 继承 代码 禁止      更新时间:2023-10-16

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

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继承protected修饰符:

class FurtherDerived : protected Derived {
};

会发生什么?assert如何被触发?

如果您有ProtectedPrivate继承,您不能:

Base *ptr = new Derived();

你也做不到,

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

这是因为BaseDerived的不可访问的基

由于不能使用Base类指针指向Derived类对象,该检查看起来是多余的。


编辑:


即使不能将Derived类对象直接赋值给Base类指针,也可以通过以下方式实现:如果Derived类的函数返回Base类指针。

简而言之,Base类指针可以指向Derived类对象,即使派生为protectedprivate

鉴于上述,

根据c++标准:
5.2.7.8:

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

注意,标准特别要求派生为Public。
因此,如果派生是protectedprivate, dynamic_cast将检测将强制转换视为不正确的强制转换,并返回NULL(因为您正在使用指针),并且将调用assert

所以是的,代码是非常有效的。它确实做到了注释所说的


这个示例演示了它按照注释工作:
#include<iostream>
class Base 
{
    public:
        virtual bool IsDerived() const { return false; }
};
class Derived : protected Base 
{
    public:
        bool IsDerived() const { return true; }
        Base* getBase() { return this; }
};
Derived* CastToDerived( Base* base )
{
     // private and protected inheritance from Derived is prohibited
     Derived* derived = dynamic_cast<Derived*>(base);
     if( derived == 0 ) 
     {
         std::cout<< "!base->IsDerived()";
     }
     return derived;
}

int main()
{
    Derived *ptr3 = new Derived();
    Base *ptr = ptr3->getBase();
    Derived *ptr2 = CastToDerived(ptr);
    return 0;
}

IsDerived是在基类中定义的虚函数,函数是根据调用函数所使用的对象的静态类型解析的。也就是说,这不是问题。它会成功的。(也许,我在你的问题中遗漏了什么)。

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

如果BaseDerived继承为protected或private,则运行时检查将失败。

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

所以,代码是一个解决方案的私有和受保护的后代:如果你继承Derivedprotectedprivate, dynamic_cast将返回NULL和自定义检查将被执行。

我不明白这段关于私有继承和受保护继承的内容。

答案很简单。这个注释和许多其他注释一样,不是以任何方式、形状或形式描述代码的注释。

的例子:

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() << "nn";
   }
}
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语句

附录
我怀疑发生的事情是,在某些特定的机器上,在某些特定的编译器上,有问题的代码以某种方式设法完成了作者认为它应该做的事情。我怀疑作者从来没有测试过这个假定的检查,看看它是否真的像宣传的那样工作。