我最近遇到了一些狡猾的代码。但这种行为让我有点傻眼。以下是问题的简化(基本上缺少虚拟关键字,使其非多态)。为什么/如何打印“C :: foo,i:5”?
内存中的对象如何能够拥有“i”?我试过C ++ 03和C ++ 11。
#include <iostream>
using namespace std;
class P
{
public:
void foo()
{
cout << "P::foo called" << endl;
}
};
class C : public P
{
public:
void foo()
{
i = 5;
cout << "C::foo called, i: " << i << endl;
}
int i;
};
int main()
{
C* c = static_cast<C*>(new P());
c->foo();
}
答案 0 :(得分:1)
&#34;为什么/如何打印&#34; C :: foo调用,i:5&#34;?&#34;
在static_casting中指向C指针的P指针,你要对编译器说这段内存,好像它包含了一个C类对象
所以当你调用foo时,它会查找fs的Cs版本。
(这解释了C:foo叫...但不是我是怎么回事5)
&#34;记忆中的物体如何能够拥有&#39; i&#39;在它&#34;
在某种程度上它没有。被告知这个记忆包含一个C,然后编译器就会知道&#34;我住在某个内存偏移对象这个指针。该内存还没有被分配,特别是为了包含C类对象的i成员(没有创建C的对象),但被告知(错误地)内存确实包含C,它是&#l; ll将该地址用作i,并且,因为您在输出之前将其设置为foo,所以该被盗用的地址最终将包含5。
如果你没有在foo中设置i,但是当你声明它时你初始化它,你会看到一个真正的C对象输出你设置它的值,但是一个P *强制转换为一个C *输出恰好在该地址的任何内容。
答案 1 :(得分:0)
这正是预期的行为,对此并不奇怪。 “笔记 static_cast也可用于通过执行到特定类型的函数到指针转换来消除函数重载的歧义“
http://en.cppreference.com/w/cpp/language/static_cast
我现在无法验证,但在子对象的实例中,您应该能够通过指定命名空间来指定要调用的两个“foo”中的哪一个。但是当发生静态转换时不确定。
void C::foo()
{
if (/*something*/)
// do something
else
D::foo();
}
答案 2 :(得分:0)
经过大量研究后得出结论:“未定义的行为”
以下是使用static_cast
进行向下转换的规则,可在C ++标准的第5.2.9节([expr.static.cast]
)中找到(C ++ 0x措辞):
类型为“指向 cv1
B
的指针”的prvalue,其中B
是类类型,可以转换为类型为“指向的指针的prvalue” cv2D
“,其中D
是从B
派生的类,如果从”指向D
的指针“转换为”指向{{的指针“的有效标准转换1}}“存在, cv2 与 cv1 和B
具有相同的cv资格,或更高的cv资格 既不是B
的虚基类,也不是D
的虚基类的基类。空指针值将转换为目标类型的空指针值。如果“指向 cv1D
的指针”的prvalue指向 到B
实际上是B
类型对象的子对象,结果指针指向封闭对象 类型为D
。否则,演员表的结果是未定义的。