📜  C++ 中的动态 _Cast

📅  最后修改于: 2022-05-13 01:55:15.951000             🧑  作者: Mango

C++ 中的动态 _Cast

C++ 是一种强大的语言。在 C++ 中,我们也可以编写结构化程序和面向对象的程序。在本文中,我们将重点介绍 C++ 中的dynamic_cast 。现在在 C++ 中开始 dynamic_cast 之前,首先了解什么是 C++ 中的类型转换。

类型铸造

强制转换是一种将一种数据类型转换为另一种数据类型的技术。用于此目的的运算符称为强制转换运算符。它是一个一元运算运算符,它强制将一种数据类型转换为另一种数据类型。它采用以下格式:

句法:

方案一:



C++
// C++ program to demonstrate the use
// of typecasting
#include 
using namespace std;
  
// Driver Code
int main()
{
    // Variable declaration
    int a, b;
    float c;
  
    a = 20;
    b = 40;
  
    // Typecasting
    c = (float)a * b;
  
    cout << "Result: " << c;
  
    return 0;
}


C++
// C++ program to read the values of two
// variables and stored the result in
// third one
#include 
using namespace std;
  
int main()
{
    // Variable declaration and
    // initialization
    int a = 7, b = 2;
    float c;
    c = a / b;
  
    cout << "Result:" << c;
  
    return 0;
}


C++
// C++ program to read two variable value
// (a, b) and perform typecasting
#include 
using namespace std;
  
// Driver Code
int main()
{
    // Variable declaration and
    // initialization
    int a = 7, b = 2;
    float c;
  
    // Type Casting
    c = (float)a / b;
    cout << "Result :" << c;
  
    return 0;
}


C++
// C++ program demonstrate if there
// is no virtual function used in
// the Base class
#include 
using namespace std;
  
// Base class declaration
class Base {
    void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived Class 1 declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived class 2 declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
  
    // Base class pointer hold Derived1
    // class object
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic casting
    Derived2* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
  
    return 0;
}


C++
// C++ Program demonstrates successful
// dynamic casting and it returns a
// value of type new_type
#include 
  
using namespace std;
// Base Class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
  
    // Base class pointer holding
    // Derived1 Class object
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic_casting
    Derived1* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
    else
        cout << "not null" << endl;
  
    return 0;
}


C++
// C++ Program demonstrate if the cast
// fails and new_type is a pointer type
// it returns a null pointer of that type
#include 
using namespace std;
  
// Base class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic Casting
    Derived2* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
  
    return 0;
}


C++
// C++ Program demonstrate if the cast
// fails and new_type is a reference
// type it throws an exception
#include 
#include 
using namespace std;
  
// Base class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
    Base* bp = dynamic_cast(&d1);
  
    // Type casting
    Derived1* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
    else
        cout << "not null" << endl;
  
    // Exception handling block
    try {
        Derived2& r1 = dynamic_cast(d1);
    }
    catch (std::exception& e) {
        cout << e.what() << endl;
    }
  
    return 0;
}


输出:
Result: 800

说明:在上面的例子中,首先将变量a转换为float然后乘以b ,现在结果也是 float float ,然后将结果分配给变量c 。现在, c 的值为800

方案二:

C++

// C++ program to read the values of two
// variables and stored the result in
// third one
#include 
using namespace std;
  
int main()
{
    // Variable declaration and
    // initialization
    int a = 7, b = 2;
    float c;
    c = a / b;
  
    cout << "Result:" << c;
  
    return 0;
}
输出:
Result:3

说明:在上述情况下,变量c3 ,而不是3.5 ,因为变量ab都是整数类型,因此a/b也是整数类型。计算完a/b 后,将int类型的变量分配给浮点类型的变量c 。但是a/bint类型,即7/23 ,而不是3.5 。因此,变量c 的值为3

方案三:

C++

// C++ program to read two variable value
// (a, b) and perform typecasting
#include 
using namespace std;
  
// Driver Code
int main()
{
    // Variable declaration and
    // initialization
    int a = 7, b = 2;
    float c;
  
    // Type Casting
    c = (float)a / b;
    cout << "Result :" << c;
  
    return 0;
}
输出:
Result :3.5

解释:现在,变量c3.5 ,因为在上面的表达式中,首先a被转换为float因此a/b也是float类型。 7.0/23.5 。然后将其分配给变量c



C++ 支持四种类型的转换:

静态转换这是可以使用的最简单的转换类型。它是一个编译时强制转换。它执行类型之间的隐式转换(例如 int 到 float 或指向 void* 的指针),并且它还可以调用显式转换函数(或隐式转换函数)。

动态转换:转换是一种将数据从一种类型转换为另一种类型的运算符。在 C++ 中,动态转换主要用于运行时的安全向下转换。要处理dynamic_cast ,基类中必须有一个虚函数。 dynamic_cast仅适用于多态基类,因为它使用此信息来决定安全向下转换。

句法:

  • 向下转换将基类指针(或引用)转换为派生类指针(或引用)称为向下转换。在图 1 中,从基类指针/引用转换为“派生类 1”指针/引用,显示向下转换(基类 -> 派生类)。

  • 向上转换:将派生类指针(或引用)转换为基类指针(或引用)称为向上转换。在图 1 中,从派生类 2 指针/引用到“基类”指针/引用的转换显示了向上转换(派生类 2 -> 基类)。

正如我们上面提到的动态转换必须有一个 Virtual 函数。假设如果我们不使用虚函数,那么结果是什么?

在这种情况下,它会生成一条错误消息“源类型不是多态的”。

C++



// C++ program demonstrate if there
// is no virtual function used in
// the Base class
#include 
using namespace std;
  
// Base class declaration
class Base {
    void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived Class 1 declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived class 2 declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
  
    // Base class pointer hold Derived1
    // class object
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic casting
    Derived2* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
  
    return 0;
}
输出:
not null

虚函数包括运行时类型信息,基类中没有虚函数。所以这段代码会产生一个错误。

案例 1:让我们举一个dynamic_cast的例子,它演示了如果转换成功,它会返回一个new_type类型的值。

C++

// C++ Program demonstrates successful
// dynamic casting and it returns a
// value of type new_type
#include 
  
using namespace std;
// Base Class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
  
    // Base class pointer holding
    // Derived1 Class object
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic_casting
    Derived1* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
    else
        cout << "not null" << endl;
  
    return 0;
}
输出:
not null

说明:在这个程序中,有一个基类和两个派生类(Derived1、Derived2),这里基类指针持有派生类1对象(d1)。在dynamic_casting基类时,指针持有 Derived1 对象并将其分配给派生类 1,分配有效的dynamic_casting

情况 2:现在,如果转换失败并且 new_type 是指针类型,则返回该类型的空指针。

C++

// C++ Program demonstrate if the cast
// fails and new_type is a pointer type
// it returns a null pointer of that type
#include 
using namespace std;
  
// Base class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class declaration
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class declaration
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
    Base* bp = dynamic_cast(&d1);
  
    // Dynamic Casting
    Derived2* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
  
    return 0;
}
输出:
null

说明:在这个程序中,在dynamic_casting基类指针持有Derived1对象并将其分配给派生类2时,这是无效的dynamic_casting。因此,它在结果中返回该类型的空指针。

情况 3:现在再看一个 dynamic_cast 的情况,如果转换失败并且 new_type 是引用类型,它会抛出一个与 std::bad_cast 类型的处理程序匹配的异常并给出警告:“Derived d1”的 dynamic_cast 到“class” Derived2&”永远不会成功。

C++

// C++ Program demonstrate if the cast
// fails and new_type is a reference
// type it throws an exception
#include 
#include 
using namespace std;
  
// Base class declaration
class Base {
    virtual void print()
    {
        cout << "Base" << endl;
    }
};
  
// Derived1 class
class Derived1 : public Base {
    void print()
    {
        cout << "Derived1" << endl;
    }
};
  
// Derived2 class
class Derived2 : public Base {
    void print()
    {
        cout << "Derived2" << endl;
    }
};
  
// Driver Code
int main()
{
    Derived1 d1;
    Base* bp = dynamic_cast(&d1);
  
    // Type casting
    Derived1* dp2 = dynamic_cast(bp);
    if (dp2 == nullptr)
        cout << "null" << endl;
    else
        cout << "not null" << endl;
  
    // Exception handling block
    try {
        Derived2& r1 = dynamic_cast(d1);
    }
    catch (std::exception& e) {
        cout << e.what() << endl;
    }
  
    return 0;
}

输出:

笔记:

  • Dynamic_cast 具有运行时开销,因为它在运行时使用“运行时类型信息”检查对象类型。
  • 如果有一个保证我们永远不会转换到错误的对象,那么总是避免 dynamic_cast 并使用 static_cast。
想要从精选的视频和练习题中学习,请查看C++ 基础课程,从基础到高级 C++ 和C++ STL 课程,了解语言和 STL。要完成从学习语言到 DS Algo 等的准备工作,请参阅完整的面试准备课程