C++ Run-time type information

static binding和dynamic binding

Binding一般指的将一个物体绑定到另外一个物体上,C++编译时指的Binding是,将函数调用和函数具体的定义连接到一起。在C++里,当函数被调用时,程序会把对应函数的定义部分链接到函数的声明处。
在这里插入图片描述
Binding分为static和dynamic binding两种,区别为:

  • static binding位于编译期,后者位于运行期,所以也叫early binding和late binding。
  • 如果一个函数被调用时的参数能在编译期决定,那么就属于static binding,否则是dynamic binding。
  • 函数重载,运算符重载和普通的函数调用都是static binding,而dynamic binding只能通过virtual functions
  • static binding更快,但dynamic binding更灵活

RTTI

run-time type information or run-time type identification (RTTI),可以用于在运行时知道Object的类型,需要添加头文件typeinfo,具体用法如下:

//The typeid operator retrieves a std::type_info object describing the most derived type of an object:
// typeid返回的类型为std::type_info
if (typeid(Person) == typeid(*obj)) {
    
    
  serialize_person( obj );
}

举一个例子,代码如下所示:

#include <iostream>
#include <typeinfo>

class Person {
    
    
public:
	virtual ~Person() = default;
};

class Employee : public Person {
    
    };

int main() {
    
    
	Person person;
	Employee employee;
	Person* ptr = &employee;
	Person& ref = employee;

	// The string returned by typeid::name is implementation-defined.
	std::cout << typeid(person).name()
		<< std::endl;  // Person (statically known at compile-time).
	std::cout << typeid(employee).name()
		<< std::endl;  // Employee (statically known at compile-time).
	std::cout << typeid(ptr).name()
		<< std::endl;  // Person* (statically known at compile-time).
	std::cout << typeid(*ptr).name()
		<< std::endl;  // Employee (looked up dynamically at run-time
					   //           because it is the dereference of a
					   //           pointer to a polymorphic class).
	std::cout << typeid(ref).name()
		<< std::endl;  // Employee (references can also be polymorphic)
}

输出如下:

class Person
class Employee
class Person *
class Employee
class Employee

普通的数据类型也可以输出:

std::cout << typeid(6.0f).name() << std::endl; // 输出float
std::cout << typeid(6).name() << std::endl; // 输出int

RTII可以在Runtime得知类的类型,可以用于dynamic_cast函数,不过RTII会造成性能开销,相关链接参考https://stackoverflow.com/questions/579887/how-expensive-is-rtti

dynamic_cast

dynamic_cast用于基类对象和派生类对象之间的转换,尤其是用于基类对象向派生类对象的转换
正常的如果直接进行强转,如果转错了会报错,而用dynamic_cast进行转换,如果转换错误,不会报错,而是会返回一个空指针,从而可以进行条件判断,举个例子:

class Entity{
    
    } // Entity是基类
class Enemy : public Enity{
    
    } // 子类
class Player : public Enity{
    
    } // 子类

如果输入一个对象A,A的类型为Entity,但是我不知道具体是Enemy还是Player类型,如果正常的(Player)A,是不行的,这个时候就通过dynamic_cast<Player>来进行转换。注意dynamic_cast必须用于运行时,也就是说转换的对象里必须包含多态属性,基类里需要有虚函数,一般的基类都会有虚函数(虚析构函数)。

那么dynamic_cast怎么判断对象A是Enemy对象还是Player对象呢,它就是通过RTTI来判断的,在VS2017里,可以对其进行设置,如下图所示:

在这里插入图片描述

如果我们关掉RTTI的功能,原本可以成功运行的代码就会报错,代码如下所示:

#include <iostream>
#include <typeinfo>

class Person {
    
    
public:
	virtual ~Person() = default;
};
class Employee : public Person {
    
    };
int main() {
    
    
	Person *p = new Employee();

	Employee* p0 = dynamic_cast<Employee*>(p);
}

关掉RTII后会报错,如下图所示:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/alexhu2010q/article/details/108118681