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

发布于 2024-12-01 09:04:50 字数 662 浏览 3 评论 0原文

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

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

我没有得到有关私有和受保护继承的段落。

假设我使用 protected 修饰符从 Derived 继承:

class FurtherDerived : protected Derived {
};

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

I found some rather strange code:

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

I don't get the passage about private and protected inheritance.

Suppose, I inherit from Derived with protected modifier:

class FurtherDerived : protected Derived {
};

What happens? How will that assert get triggered?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

滿滿的愛 2024-12-08 09:04:50

如果您有 ProtectedPrivate 继承,您不能这样做:

Base *ptr = new Derived();

您也不能这样做,

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

这是因为,BaseBase 的不可访问的基础code>Derived

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


编辑:
即使您无法直接将 Derived 类对象分配给 Base 类指针,也可能以其他方式发生这种情况,例如:如果 Derived 的函数code> 类返回一个 Base 类指针。

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

鉴于上述情况,

根据 C++ 标准:
5.2.7.8:

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

请注意,该标准明确要求推导必须公开。
因此,如果派生是受保护的或私有的,则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;
}

If you have a Protected or Private Inheritance, You cannot do:

Base *ptr = new Derived();

neither can you do,

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

This is because, Base is an inaccessible base of Derived

Since you cannot have a Base class pointer pointing to Derived class object, that check looks redundant.


EDIT:
Even if you cannot directly assign an Derived class object to an Base class pointer, It can happen so in some other ways like: If a function of Derived class returns a Base class pointer.

In short, A Base class pointer may point to a Derived class object even if derivation is protected or private.

Given the above,

As per C++ standard:
5.2.7.8:

The run-time check logically executes as follows:
— If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class sub- object of a T object, and if only one object of type T is derived from the sub-object pointed (referred) to by v, the result is a pointer (an lvalue referring) to that T object.
Otherwise, if v points (refers) to a public base class sub-object of the most derived object, and the type of the most derived object has a base class, of type T, that is unambiguous and public, the result is a pointer (an lvalue referring) to the T sub-object of the most derived object.
— Otherwise, the run-time check fails.

Note that the standard specifically imposes the requirement of the derivation to be, Public.
Thus dynamic_cast will detect the treat the cast as an improper cast if derivation is protected or private and return a NULL(since you are using a pointer) and the assert will be called.

So Yes, the code is very much valid. And it indeed does what the comment says


This sample, demonstrates that it works as per the comments:

#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;
}
相思故 2024-12-08 09:04:50

IsDerived 是在基类中定义的虚拟函数,函数根据调用该函数所使用的对象的静态类型进行解析。这意味着,这不是问题。它会起作用的。 (或者也许,我错过了你问题中的一些内容)。

IsDerived is a virtual function defined in the base class, and the functions are resolved based on the static type of the object using which you invoke the function. That means, that's not a problem. It will work. (Or maybe, I missed something in your question).

病女 2024-12-08 09:04:50

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

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

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

因此,该代码是私有和受保护后代的解决方法:如果您使用 protectedprivate 继承 Derived,则 dynamic_cast 将返回 NULL 并且将执行自定义检查。

dynamic_cast performs run-time check (5.2.7/8).

The runtime check will fail, if Base is inherited as protected or private by Derived.

The value of failed run-time check when casting to a pointer is a NULL pointer (5.2.7/9).

So, the code is a workaround for private and protected descendants: if you inherit Derived with protected or private, dynamic_cast will return NULL and the custom check will be performed.

2024-12-08 09:04:50

我不明白有关私有继承和受保护继承的段落。

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

示例:

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 语句。

附录
我怀疑发生的事情是,在具有特定编译器的特定机器上,相关代码确实以某种方式设法完成了作者认为它应该做的事情。我怀疑作者从未测试过这个所谓的检查,看看它是否真的像广告中那样有效。

I don't get the passage about private and protected inheritance.

The answer is simple. This comment like many, many other comments, is a comment that does not describe the code in any way, shape, or form.

Example:

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

Tested with multiple versions of gcc and clang; none of them raised that assert statement.

Addendum
I suspect that what happened was that on some particular machine with some particular compiler, the code in question did somehow manage to do what the author thought it should do. I suspect that the author never tested this supposed check to see if it actually worked as advertised.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文