C++ 静态_cast如何影响虚拟函数调用?

C++ 静态_cast如何影响虚拟函数调用?,c++,C++,我的以下代码从中被盗: 打印输出为:分段错误:11 老实说,我两个都不太明白。有人能解释一下基于上述例子的静态和虚拟方法之间的复杂性吗?顺便说一句,如果我希望打印输出是派生的::foo?在第二个示例中,由于没有实例化基指针,所以选择了segfult。因此,没有可调用的v表。尝试: Base * base = new Base(); Derived* _1 = static_cast<Derived*>(base); _1->foo(); 这将打印Base::foo 这个问题毫

我的以下代码从中被盗:

打印输出为:分段错误:11


老实说,我两个都不太明白。有人能解释一下基于上述例子的静态和虚拟方法之间的复杂性吗?顺便说一句,如果我希望打印输出是派生的::foo?

在第二个示例中,由于没有实例化基指针,所以选择了segfult。因此,没有可调用的v表。尝试:

Base * base = new Base();
Derived* _1 = static_cast<Derived*>(base);
_1->foo();
这将打印Base::foo

这个问题毫无意义,因为静态_转换不会影响v形表。但是,这使得非虚拟功能更具意义:

class Base
{
public:
   void foo() { std::cout << "Base::foo() \n"; }
};

class Derived : public Base
{
public:
    void foo() { std::cout << "Derived::foo() \n"; }
};


int main()
{
   Base base;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

这个将输出派生::foo。然而,这是一个非常错误的代码,虽然它编译了,但行为未定义。

在第二个示例中,您之所以选择了segfault,是因为您没有实例化基指针。因此,没有可调用的v表。尝试:

Base * base = new Base();
Derived* _1 = static_cast<Derived*>(base);
_1->foo();
这将打印Base::foo

这个问题毫无意义,因为静态_转换不会影响v形表。但是,这使得非虚拟功能更具意义:

class Base
{
public:
   void foo() { std::cout << "Base::foo() \n"; }
};

class Derived : public Base
{
public:
    void foo() { std::cout << "Derived::foo() \n"; }
};


int main()
{
   Base base;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

这个将输出派生::foo。然而,这是一个非常错误的代码,尽管它可以编译,但其行为是未定义的。

虚拟函数的全部目的是变量的静态类型不应该重要。编译器将查找对象本身的实际实现,通常在对象中隐藏一个vtable指针。静态类型转换应该没有任何影响。

虚拟函数的全部目的是变量的静态类型不应该重要。编译器将查找对象本身的实际实现,通常在对象中隐藏一个vtable指针。静态\u转换应该无效。

指向指针或引用类型的有效静态\u转换根本不会影响虚拟调用。根据对象的动态类型解析虚拟调用。对指针或引用的静态转换不会更改实际对象的动态类型

不过,您在示例中观察到的输出并不相关。这些例子都是断章取义的

第一个进行无效的静态\u转换。在基础对象未派生的情况下,不允许将Base&强制转换为派生对象。任何执行此类强制转换的尝试都会产生未定义的行为

下面是一个有效应用静态_cast进行引用类型向下转换的示例

int main()
{
   Derived derived;
   Base &base = derived;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}
在第二个示例中,由于与任何强制转换或虚拟调用无关的原因,代码被完全破坏。代码试图操作未初始化的指针-行为未定义。

对指针或引用类型的有效静态转换根本不会影响虚拟调用。根据对象的动态类型解析虚拟调用。对指针或引用的静态转换不会更改实际对象的动态类型

不过,您在示例中观察到的输出并不相关。这些例子都是断章取义的

第一个进行无效的静态\u转换。在基础对象未派生的情况下,不允许将Base&强制转换为派生对象。任何执行此类强制转换的尝试都会产生未定义的行为

下面是一个有效应用静态_cast进行引用类型向下转换的示例

int main()
{
   Derived derived;
   Base &base = derived;
   Derived& _1 = static_cast<Derived&>(base);
   _1.foo();
}

在第二个示例中,由于与任何强制转换或虚拟调用无关的原因,代码被完全破坏。代码试图操作未初始化的指针-行为未定义。

在两个示例中,行为均未定义。基对象不是派生对象,告诉编译器假装它是派生对象并不能使它成为派生对象。获取打印出派生::foo的代码的方法是使用派生类型的对象。

在这两个示例中,行为都未定义。基对象不是派生对象,告诉编译器假装它是派生对象并不能使它成为派生对象。获取打印出派生::foo的代码的方法是使用派生类型的对象。

如果调用未初始化的指针,分段错误实际上是最好的结果。对于要派生的打印输出::foo,您需要确保派生类型的实例化存在,这两个例子中都没有,因为并没有任何实际的对象,所以你们会对指针产生错误。只是还没有指向任何的指针。因此_1->foo尝试从随机内存位置读取虚拟表。如果将指针更改为Base;派生*_1=静态_铸造和基础;然后,您可以尝试调用foo,但仍然应该得到Base::foo,因为对象就是这样的。要获得派生::foo,您需要一个派生的_2_2.foo.如果对未初始化的指针进行调用,分段错误实际上是最好的结果。对于要派生的打印输出::foo,您需要确保派生类型的实例化存在,而这在两个示例中都不存在。使用指针分段错误是因为
“没有任何实际对象。只是还没有指向任何的指针。因此_1->foo尝试从随机内存位置读取虚拟表。如果将指针更改为Base;派生*_1=静态_铸造和基础;然后,您可以尝试调用foo,但仍然应该得到Base::foo,因为对象就是这样的。要获得派生::foo,您需要一个派生的_2_2.foo.这个例子仍然不成立。当源引用未引用派生类型的[sub-]对象时,将Base和强制转换为派生对象是非法的。在你的例子中,这个行为是未定义的。它可能是非法的,是的,我猜它是未定义的,所以它可能在答案中没有它的位置。但人们可能会问自己,为什么这会编译并给出这个输出。我将编辑答案,谢谢。这个例子仍然是错误的。当源引用未引用派生类型的[sub-]对象时,将Base和强制转换为派生对象是非法的。在你的例子中,这个行为是未定义的。它可能是非法的,是的,我猜它是未定义的,所以它可能在答案中没有它的位置。但人们可能会问自己,为什么这会编译并给出这个输出。我将编辑答案,谢谢。