对私有范围内的私有继承进行动态向下转换 [英] Dynamic downcast on private inheritance within private scope

查看:187
本文介绍了对私有范围内的私有继承进行动态向下转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题的调整进入。考虑:

  class A {}; 

class B:private A {
static void foo();
};

void B :: foo(){
B * bPtr1 = new B;
A * aPtr1 = dynamic_cast< A *>(bPtr1); //给指针
B * bPtr2 = dynamic_cast< B *>(aPtr1); // given NULL
}

由于 aPtr1 实际上是 B * 类型,因为我们完全访问了 B 它从 A 的继承,我希望两个casts工作。但他们不;为什么?



请注意:




  • 如果 foo()不是B的成员,这两个类型都会失败。

  • 如果 B

>解决方案

5.2.7(ISO / IEC 14882,12/29/2003)在这一点上非常明确:


[关于表达式 dynamic_cast< T>(v)]



如果 T ispointer to cv1 B and v B 的类型指向 cv2
D 基本类 D ,结果是一个
指向唯一 B 子对象的指针 v 指向的 D 对象。
[... bla bla about cv1 and cv2 ...] 且B应为D (强调我)的可访问的无歧义基类
>


(回忆11.2 如果基类的发明的公共成员可访问, 。)。



这解释了为什么第一次施法。现在,第二个:



应用运行时检查以查看指向的对象或由 v 引用的
是否可以转换为指向的类型或引用
T



运行时检查逻辑执行如下:




  • 如果在 v v
    (引用)到 public 基类子对象,如果只有
    ,那么类型T的一个对象是从子对象指向(引用)
    v 派生的,结果是一个指针 c>
    对象

  • 否则,如果 v 点(指)到最导出对象的 public 基类子对象
    ,以及最导出对象的类型
    具有 T
    类型的基类,即明确和 public
    结果是指向
    最大派生对象的 T 子对象的指针(引用一个左值)。

  • <否则,运行时检查失败。


失败的指针类型的值为空指针值
所需的结果类型。失败的转换为引用类型throws
bad_cast(18.5.2)。


由于 private 继承:即使基类是可访问的,也不是 public ,并且标准需要 public ,不可访问。



烦人,不是吗?我没有C ++ 0x草案方便,也许有人可以编辑我的答案与它的引号,万一发生了变化。


有另一种方法来实现这个演员吗?


这取决于你想做什么。基本上,私有继承只是执行组合的另一个设备。如果你真的要返回一个指向私有派生实例的指针,那么要么使继承公开,要么返回成员。



无论如何,你很高兴知道 static_cast 似乎没有此限制:


5.2.9。 [about static_cast< T>(v)] [...]



cv1 B,其中B是类类型,可以转换为类型指针
到cv2 D的右值,其中D是从B导出的类(第10条),如果有效标准从指针到D
到指向B的指针的转换存在
(4.10),cv2与cv1具有相同的cv-qualification,不是D的虚拟基类。空指针值(4.10)将转换为
目标类型的空指针值。如果类型指向cv1 B的指针的右值指向一个实际上是类型为D的
对象的子对象的B,则生成的指针指向类型D的包围对象。否则,结果
cast是未定义的。


所以如果你知道指针的实际动态类型,允许 static_cast 内部 foo



对有关为什么存在此不一致性的任何其他信息感兴趣。


A tweak on this question that I've run into. Consider:

class A {};

class B : private A {
   static void foo();
};

void B::foo(){
   B* bPtr1 = new B;
   A* aPtr1 = dynamic_cast<A*>(bPtr1); // gives pointer
   B* bPtr2 = dynamic_cast<B*>(aPtr1); // gives NULL
}

Since aPtr1 is, in fact, of type B*, and since we've got full access to B and its inheritance from A, I'd expected both casts to work. But they don't; why? Is there another way to achieve this cast?

Note that:

  • If foo() were not a member of B, both casts would fail.
  • If B inherits from A publicly, both casts would work.

解决方案

5.2.7 (ISO/IEC 14882, 12/29/2003) is pretty explicit on this point:

[about the expression dynamic_cast<T>(v)]

If T is "pointer to cv1 B" and v has type "pointer to cv2 D" such that B is a base class of D, the result is a pointer to the unique B sub-object of the D object pointed to by v. [... bla bla about cv1 and cv2 ...] and B shall be an accessible unambiguous base class of D (emphasis mine)

(recall 11.2 "A base class is said to be accessible if an invented public member of the base class is accessible.").

This explains why the first cast works. Now, for the second:

[...]

Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.

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 subobject 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.

The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws bad_cast (18.5.2).

So it seems that the behavior you observe is due to the private inheritance: even if the base class is accessible, it is not public, and the standard requires public, not accessible.

Annoying, isn't it ? I don't have the C++0x draft handy, perhaps someone can edit my answer with quotes from it, in case things have changed.

Is there another way to achieve this cast?

It depends on what you want to do. Basically, private inheritance is just another device for performing composition. If you really are to return a pointer to the private derived instance, then either make the inheritance public, or return a member.

Anyways, you'll happy to know that static_cast doesn't seem to have this limitation:

5.2.9. [about static_cast<T>(v)] [...]

An rvalue of type "pointer to cv1 B", where B is a class type, can be converted to an rvalue of type "pointer to cv2 D", where D is a class derived (clause 10) from B, if a valid standard conversion from "pointer to D" to "pointer to B" exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. The null pointer value (4.10) is converted to the null pointer value of the destination type. If the rvalue of type "pointer to cv1 B" points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

so if you know for sure what the actual dynamic type of the pointer is, you are allowed to static_cast inside foo.

I'd be interested in any additional information about why this inconsistency exists.

这篇关于对私有范围内的私有继承进行动态向下转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆