难以理解C风格的类型转换和动态转换

时间:2016-09-26 04:02:22

标签: c++ casting

我一直在尝试理解C ++中的类型转换。在下面的代码中,类B是类A的子类,并且都具有多态关系。

#include <iostream>
using namespace std;
class A{
    int a;
    public:
        virtual void sayhello() {cout<<"Hello from A"<<endl;}
};
class B:public A{
    int b;
    public:
        void sayhello(){cout<<"Hello from B"<<endl;}
        void another_func(){cout<<"Hello from B::another_func"<<endl;}
};
int main() {

    A *temp1 = new A;
    //Statement 1
    B *b =(B*) temp1;

    //Statement 2
    //B* b = dynamic_cast<B*>(temp1);


    b->another_func();

    delete temp1;
    return 0;
}

以上程序的输出 -

Hello from B::another_func

我很难理解以下问题 -
1)对于语句1我们如何将父对象强制转换为子对象。逻辑上这应该是不正确的,因为现在我们已经扩展了这个对象的功能(同一个对象现在可以访问子类函数another_func)。

Java中的类似代码会产生错误 -

“不兼容的类型:A无法转换为B
        B b =(A)temp;“

现在,如果我们评论声明1&amp;取消声明2声明2发生类似的事情。

那么,为什么C ++允许这样呢?

2)现在,如果我们从两个类中删除了sayhello()函数,使得它们没有多态关系,则dynamic_cast的语句2不再起作用(因为我们知道dynamic_cast可以降低多态类),但c语言强制转换为语句1仍然产生相同的输出 所以我们可以说c-style强制转换不是基于类之间的多态关系。
基于哪种c型演员发生的参数是什么?

2 个答案:

答案 0 :(得分:4)

假设您切换注释以便注释C样式强制转换,并取消注释dynamic_cast。此外,修改代码使其成为:

B* b = dynamic_cast<B*>(temp1);
if(b == nullptr)
    cout << "not really a B" << endl;
else
    b->another_func();

然后在运行代码时,它打印出“不是真正的B”。

如果你看what dynamic_cast does

  

如果强制转换成功,dynamic_cast将返回new_type类型的值。如果转换失败并且new_type是指针类型,则返回该类型的空指针。

因此,使用dynamic_cast的版本是未定义的行为,因为您取消引用指针而不检查转换是否失败。

现在使用C-Style演员的所有不同版本。 The rules是:

  

当遇到C风格的强制转换表达式时,编译器会尝试按以下顺序将其解释为以下强制转换表达式:

     

a)const_cast(表达式);

     

b)static_cast(expression),带有扩展:指向派生类的指针或引用另外允许转换为指针或引用明确的基类(反之亦然),即使基类是不可访问的(即,这个强制转换会忽略私有继承说明符)。同样适用于将指向成员的指针转换为指向非虚拟非虚拟基础成员的指针;

     

c)static_cast(带扩展名),后跟const_cast;

     

d)reinterpret_cast(表达);

     

e)reinterpret_cast后跟const_cast。   即使无法编译,也会选择满足相应铸造操作员要求的第一个选择(参见示例)。如果强制转换可以多种方式解释为static_cast,后跟const_cast,则无法进行编译。

根据这些规则,您的C风格演员阵容相当于

B *b = static_cast<B *>(temp1);

由于temp1实际上指向A对象,因此取消引用结果也是未定义的行为(但出于不同的原因)。

一些一般观点:

  1. C ++演员表是C风格演员表的精细版本。如果你必须演员,喜欢他们。您可以向编译器传达您正在投射的方面。

  2. 在任何情况下,你都应该尽量避免施法。如果 使用dynamic_cast,请检查结果。

答案 1 :(得分:1)

未选中C风格的演员表。在您的情况下,它只是告诉编译器将指针temp1视为类型B。使用您的代码这是一个谎言,并以任何形式使用此指针将导致未定义的行为。未定义行为的一个结果是它会以某种方式实现您所期望的。 C风格的强制转换是从C继承的,需要大量的C代码才能用C ++编译。

有时C风格的演员会做正确的事情,但他们可以执行多种不同的转换,而且通常不会立即清楚他们执行的操作:演员(T)x可以等同于reinterpret_cast<T>(x)static_cast<T>(x)const_cast<T>(x)或其组合。通常,只有static_cast<T>(x)const_cast<T>(x)的组合会产生明确定义的结果,即使这样,也会有一些未经检查的前置条件。例如,仅当使用p生成B时,才使用D将指针static_cast<D*>(p)转换为基础p指向派生D的指针D直接将B指针转换为> Error: A problem occurred configuring project ':app'. > Could not resolve all dependencies for configuration ':app:_debugCompile'. > Could not find com.android.support:multidex:1.0.1. Searched in the following locations: https://jcenter.bintray.com/com/android/support/multidex/1.0.1/multidex-1.0.1.pom https://jcenter.bintray.com/com/android/support/multidex/1.0.1/multidex-1.0.1.jar https://jitpack.io/com/android/support/multidex/1.0.1/multidex-1.0.1.pom https://jitpack.io/com/android/support/multidex/1.0.1/multidex-1.0.1.jar file:/C:/Users/as/AppData/Local/Android/sdk/extras/android/m2repository/com/android/support/multidex/1.0.1/multidex-1.0.1.pom file:/C:/Users/as/AppData/Local/Android/sdk/extras/android/m2repository/com/android/support/multidex/1.0.1/multidex-1.0.1.jar file:/C:/Users/as/AppData/Local/Android/sdk/extras/google/m2repository/com/android/support/multidex/1.0.1/multidex-1.0.1.pom file:/C:/Users/as/AppData/Local/Android/sdk/extras/google/m2repository/com/android/support/multidex/1.0.1/multidex-1.0.1.jar Required by: ElalaSeller:app:unspecified 指针。