我发现了一些相当奇怪的代码:
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 {
};
?
答案 0 :(得分:1)
如果您有Protected
或Private
继承,则无法执行此操作:
Base *ptr = new Derived();
你也不能这样做,
Derived *ptr1 = new Derived();
Base *ptr = ptr1;
这是因为,Base
是Derived
由于您不能将 Base
类指针指向Derived
类对象,因此该检查看起来多余。
修改强>
即使您不能直接将Derived
类对象分配给Base
类指针,也可以通过以下其他方式实现:如果Derived
类的函数返回{{1}类指针。
简而言之,即使派生是Base
或Base
,A Derived
类指针也可能指向protected
类对象。
鉴于上述情况,
根据C ++标准:
5.2.7.8:
运行时检查按逻辑执行如下:
- 如果在由v指向(引用)的大多数派生对象中,v指向(引用)T对象的公共基类子对象,并且如果只有一个对象类型T是从指向的子对象派生的(参考)v,结果是指向该T对象的指针(左值引用) - 否则,如果v指向(引用)最派生对象的公共基类子对象,并且最派生对象的类型具有类型为T的基类,则这是明确的,private
,结果是指向最派生对象的 的T子对象的指针(左值引用)。
- 否则,运行时检查失败。
请注意,该标准明确规定派生要求为公开。
因此,如果推导为public
或dynamic_cast
并且返回protected
(因为您正在使用指针)和{{private
,NULL
将检测将投射视为不正确的投射。 1}}将被调用。
是的,代码非常有效。它确实做了评论所说的
这个 sample ,证明它符合评论:
assert
答案 1 :(得分:0)
IsDerived
是基类中定义的虚函数,函数根据您调用函数的对象的 static 类型进行解析。这意味着,这不是问题。它会工作。 (或许,我错过了你的问题)。
答案 2 :(得分:0)
dynamic_cast
执行运行时检查(5.2.7 / 8)。
如果Base
被Derived
继承为受保护或私有,则运行时检查将失败。
转换为指针时失败的运行时检查值是NULL指针(5.2.7 / 9)。
因此,代码是私有和受保护后代的变通方法:如果您使用Derived
或protected
继承private
,dynamic_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
陈述。
<强>附录强>
我怀疑所发生的事情是在一些特定的机器上使用某些特定的编译器,所讨论的代码确实设法做了作者认为它应该做的事情。我怀疑作者从来没有测试过这个假设的支票,看看它是否真的像宣传的那样有效。