C++虚函数、static_cast、dynamic_cast

发布时间 2023-07-30 17:22:32作者: 韓さん

       C++虚函数:当一个类中拥有至少一个虚函数,那么编译器就会构建出一个虚函数表来指示这些函数的地址,假如继承该类的子类定义并实现了一个同名并具有同样函数签名的方法重写了基类中的方法,那么虚函数表会将该函数指向新的地址。
       此时多态性就体现出来了:当我们将基类的指针或引用指向子类的对象的时候,调用方法时,就会顺着虚函数表找到对应子类的方法而非基类的方法。
       当然虚函数表的存在对于效率上会有一定的影响,首先构建虚函数表需要时间,根据虚函数表寻到到函数也需要时间。
       因为这个原因如果没有继承的需要,一般不必在类中定义虚函数。但是对于继承来说,虚函数就变得很重要了,这不仅仅是实现多态性的一个重要标志,同时也是dynamic_cast转换能够进行的前提条件。

 

static_cast< new_type >(expression)
dynamic_cast< new_type >(expression)

new_type:目标数据类型 expression:原始数据类型变量或者表达式

1、static_cast:

(1) 用于类层次结构中基类和派生类之间指针或引用的转换;
上行转换: (把派生类的指针或引用转换成基类表示)是安全的。
下行转换: (把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
(2) 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。
(3) 把空指针转换成目标类型的空指针。
(4) 把任何类型的表达式转换成void类型

注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性

尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代。

/*基本类型数据转换*/
char a = 'a';
int b = static_cast<char>(a);//正确,将char型数据转换成int型数据

double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针

int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据

const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性


/*类上行和下行转换:*/
class Base
{};

class Derived : public Base
{}

Base* pB = new Base();
if(Derived* pD = static_cast<Derived*>(pB))
{}//下行转换是不安全的(坚决抵制这种方法)

Derived* pD = new Derived();
if(Base* pB = static_cast<Base*>(pD))
{}//上行转换是安全的

 

2、dynamic_cast:

该运算符把expression转换成new_type类型的对象。new_type 必须是类的指针、类的引用或者void*;

如果 new_type 是类指针类型,那么expression也必须是一个指针,如果 new_type 是一个引用,那么 expression 也必须是一个引用。

dynamic_cast运算符可以在执行期决定真正的类型。

如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。

如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

/*
  B 要有虚函数,否则会编译出错;static_cast则没有这个限制。
  这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,
  只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。
*/
 class B
 {
    public:
        int num;
        virtual void fun();
 };
 class D:public B
 {
    public:
        char* sz[100];
 };
int main()
{
    B* pb;
    D* pd = dynamic_cast<D*> (pb); 
    return 0;
}