C++ 这段禁止继承的代码是如何工作的?

C++ 这段禁止继承的代码是如何工作的?,c++,inheritance,hierarchy,access-modifiers,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 inh

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

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;
}

会发生什么?该断言将如何触发?

IsDerived
是在基类中定义的虚拟函数,函数根据调用函数所使用的对象的静态类型进行解析。也就是说,这不是问题。它会起作用的。(或者,我可能遗漏了你问题中的某些内容)。

如果你有一个
受保护的
私有的
继承,你不能:

Base *ptr = new Derived();
你也不行,

Derived *ptr1 = new Derived();
Base *ptr = ptr1;
这是因为,
Base
Derived

由于不能让
Base
类指针指向
派生的
类对象,因此该检查看起来是多余的


编辑:
即使不能直接将
派生的
类对象分配给
类指针,也可以通过其他方式进行分配,例如:如果
派生的
类的函数返回一个
类指针

简而言之,
Base
类指针可能指向
派生的
类对象,即使派生受
保护
私有

鉴于上述情况,

<>按C++标准:
5.2.7.8:

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

-否则,运行时检查将失败

请注意,本标准明确规定派生的要求是公开的。
因此,如果派生受
保护
私有
,则
dynamic_cast
将检测并将该强制转换视为不正确的强制转换,并返回
NULL
(因为您使用的是指针),并且将调用
断言

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


,表明它按照以下注释工作:

#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;
}
#包括
阶级基础
{
公众:
虚拟bool IsDerived()常量{return false;}
};
派生类:受保护的基
{
公众:
bool IsDerived()常量{return true;}
Base*getBase(){返回此;}
};
派生*CastToDerived(基*Base)
{
//禁止来自派生的私有和受保护的继承
派生*派生=动态_铸造(基础);
如果(派生==0)
{
std::coutgetBase();
派生*ptr2=CastToDerived(ptr);
返回0;
}

dynamic\u cast
执行运行时检查(5.2.7/8)

如果
派生的
基继承为受保护的或私有的,则运行时检查将失败

强制转换到指针时失败的运行时检查的值为空指针(5.2.7/9)

因此,该代码是私有和受保护子体的一种变通方法:如果使用受保护的
私有继承
派生的
动态转换
将返回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() << "\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;
}
class PrivateDerivated:private-Derivated{
公众:
基础*将基础转换为基础(){
返回动态_cast(this);
}   
};  
无效检查基础(常量字符*id,基础*pbase){
如果(pbase==0){

std::请解释“我继承自使用受保护修饰符派生的”你说的是从“派生”类派生一个新的派生类,或者从“基类”的受保护继承中派生一个新的派生类?你在哪里找到了这段代码?这没有任何意义。如果
derived
不是从
base
公开继承的,那么唯一可以传递给
CastToDerived()
是一个
Base
指针,因为无法将
派生的
指针转换为
Base
指针。因此该断言永远不会被触发。@Praetorian有很多方法可以从派生的基指针获取基指针,即使基是私有祖先。例如,通过添加
Base*Derived::getBase(){返回这个;}
@Eugene Homyakov好的,很好的例子,我没有想到有一个显式的转换函数。好的,但是
CastToDerived
的调用方如何才能将
派生的
指针转换为
基的
指针,如果继承不是公共的?请参阅我在原始帖子中的另一条评论:)这个问题不是如何
派生的
她来自
Base
。这是给定的。问题是“假设,我继承了
派生的
和受保护的修饰符。会发生什么?”@David我认为这条评论的意思与它所说的不符比有一天
dynamic\u cast
神奇地返回了0更有意义。尤金:没错。我猜这条代码的作者试图解决一个问题,猜测了错误的原因,并为这个错误的猜测编写了一个不起作用的解决方案。他后来维德发现了真正的问题,但从未删除过他大部分无害的垃圾。典型的货运邪教调试东西。我说“大部分无害”,因为这是一颗即将爆炸的炸弹。总有一天有人会编写一些类
Foo:public Base
,它也会覆盖
IsDerived()
。应用

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;
}