显式转换和隐式转换

这又是一个好话题,所谓转换就是把a变成b。隐式转换就是说在我们没有主动的去转换的地方发生的转换,显示当然就是我们主动的去转换。

隐式转换:系统跟据程序的需要而自动转换

class CTest
{
public:
    CTest(int i)
    {
        qDebug() << "Test Constructor";
        m_nValue = i;
    }

    void print()
    {
        qDebug() << "Test print value: " << m_nValue;
    }

private:
    int m_nValue;
};

void printTest(CTest test)
{
    test.print();
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // 1、赋值式的隐式转换
    int a = 5;
    float b = a;        // a、赋值时,a隐式的转成了float类型
    double c = a + b;   // b、赋值时,a和b都隐式的转成了double类型
    // 类型的还有,传参,返回值时。
    qDebug() << c;

    // 2、对象类的隐式转换,20转换为GTest对象
    printTest(20);

    return app.exec();
}

运行结果:

10
Test Constructor
Test print value:  20

显式转换:又叫强制转换,代码中明确写明的转换

class CParent
{
public:
    virtual ~CParent(){}
    virtual void print()
    {
        qDebug() << "print CParent";
    }
};

class CChild : public CParent
{
public:
    virtual void print() override
    {
        qDebug() << "print CChild";
    }
};

class CTest1
{
public:
    CTest1(){}
    ~CTest1(){}
    void print()
    {
        qDebug() << "print CTest1";
    }
};

class CTest2 : public CTest1
{
public:
    CTest2(){}
    ~CTest2(){}
    void print()
    {
        qDebug() << "print CTest2";
    }
};


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // 1、赋值式的显式转换
    int a = 5;
    float b = (float)a;

    CChild *pChild = new CChild();
    // 2、static_cast : 静态转换,强制把一个类型转换为另一个类型,而不去检查运行时。
    CParent *pParent1 = static_cast<CParent*>(pChild);
    pParent1->print();

    // 3、dynamic_cast : 动态转换,强制把一个类型转换为另一个类型,会检查是否可以转换。依赖运行时态RTTI,
    // 本质上是依赖虚函数表,虚表需要类中至少含有一个虚函数才能正常使用。
    CParent *pParent2 = dynamic_cast<CParent*>(pChild);
    pParent2->print();

    // 但是我用Qt和用vs2019,下面的代码都可以运行。运行时不会出错。打印为CTest1结果也是合理的。
    CTest2 *pTest = new CTest2();
    CTest1 *pTest1 = dynamic_cast<CTest1*>(pTest);
    pTest1->print();



    // 4、const_cast : 和const的属性相关,
    const int c_a = 10;
    const int *p = &c_a;
    // a、将const指针转为非Const类型,常用,因为不能把一个const变量直接赋给一个非const变量
    int *p1 = const_cast<int*>(p);
    // b、将非const指针转为Const类型,实际中我没用过。
    const int *p2 = const_cast<const int*>(p1);

   // 5、reinterpret_cast : 跨越类别的转换,主要用于从指针A转换到指针B
    int *pReiter = &a;
    char* pC1 = reinterpret_cast<char*>(pReiter);
    qDebug() << &pC1 << " : " << pC1 << " : " << *pC1;

    int* pC2 = reinterpret_cast<int*>(pC1);
    qDebug() << &pC2 << " : " << pC2 << " : " << *pC2;

    qDebug() <<&a;


    return app.exec();
}

运行结果:

print CChild
print CChild
print CTest1
0x73fc70  :  A  :  A
0x73fc68  :  0x73fc7c  :  65
0x73fc7c

从上归纳得到:
1、static_cast、dynamic_cast :用于父子关系的转换。dynamic_cast慢一些,但更安全。
2、const_cast :用于处理const属性
3、reinterpret_cast :用于跨越类别的转换,指针转换为整型,整型转换为指针,指针类型A转换为指针类型B。

RTTI讲解

以下摘自[浅议 Dynamic_cast 和 RTTI

class Point 
{ 

public: 

   Point( float xval ); 

   virtual ~Point(); 

   float x() const; 

   static int PointCount(); 

protected: 

   virtual ostream& print( ostream &os ) const; 

   float _x; 

   static int _point_count; 

}; 

以上类的内存中模型:


2011030621295291.jpg

1、对象的内存是Point pt ,包含内内成员变量和虚函数表的地址
2、虚表的第一项是type_info for Point 里面包含 RTTI Info

type_info for Point 的数据如下:


2011030622331269.jpg

虚表上面的地址是指向一个结构 Derive::`RTTI Complete Object Locator , 这个结构指向该类的名字,和其对象继承链。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。