禁止继承的代码是如何工作的
How does this code to forbid inheritance work?
我发现了一些相当奇怪的代码:
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
继承protected
修饰符:
class FurtherDerived : protected Derived {
};
会发生什么?assert
如何被触发?
如果您有Protected
或Private
继承,您不能:
Base *ptr = new Derived();
你也做不到,
Derived *ptr1 = new Derived();
Base *ptr = ptr1;
这是因为Base
是Derived
的不可访问的基
由于不能使用Base
类指针指向Derived
类对象,该检查看起来是多余的。
编辑:
即使不能将Derived
类对象直接赋值给Base
类指针,也可以通过以下方式实现:如果Derived
类的函数返回Base
类指针。
简而言之,Base
类指针可以指向Derived
类对象,即使派生为protected
或private
。
鉴于上述,
根据c++标准:
5.2.7.8:
运行时检查逻辑上执行如下:
-如果在v指向(引用)的最派生对象中,v指向(引用)T对象的公共基类子对象,并且如果只有一个类型T的对象是从v指向(引用)的子对象派生的,则结果是指向该T对象的指针(左值引用)。
- 否则,如果v指向(引用)最派生对象的公共基类子对象,并且最派生对象的类型有一个类型为T的基类,该基类是明确的public
,则结果是指向最派生对象的T子对象的指针(左值引用)。
—否则,运行检查失败。
注意,标准特别要求派生为Public。
因此,如果派生是protected
或private
, 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;
}
IsDerived
是在基类中定义的虚函数,函数是根据调用函数所使用的对象的静态类型解析的。也就是说,这不是问题。它会成功的。(也许,我在你的问题中遗漏了什么)。
dynamic_cast
执行运行时检查(5.2.7/8)。
如果Base
被Derived
继承为protected或private,则运行时检查将失败。
转换为指针时,运行时检查失败的值为NULL指针(5.2.7/9)。
所以,代码是一个解决方案的私有和受保护的后代:如果你继承Derived
与protected
或private
, dynamic_cast
将返回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() << "nn";
}
}
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
语句
附录
我怀疑发生的事情是,在某些特定的机器上,在某些特定的编译器上,有问题的代码以某种方式设法完成了作者认为它应该做的事情。我怀疑作者从来没有测试过这个假定的检查,看看它是否真的像宣传的那样工作。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- sdl软件渲染器不工作,工作在硬件加速的一个