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