870920 Menu

SwingCoder之C++备忘录·25

typedef与typeid

typedef
类型重定义并不是创建新类型,而是给出已有数据类型的别名。语法:

typedef 原类型 新类型;

typedef类型重定义与#define宏定义的区别(最根本的差别速记:type原新,define新原):

 typedef是数据类型的别名,遵循编码、调试、编译时数据类型方面的检查机制。

 #define是编译时无条件替换,与数据类型无关。

 typedef类型重定义的语法是:typedef 原类型 新类型;

 typedef语句的末尾有分号

 #define宏定义的语法是:#define 新名字 原名字(原值,数据等)

 define宏定义末尾无分号

注意:尽量少使用或不使用#define宏定义常量或函数,用const、enum、inline代替之。不得已使用时,要及时#undef之。

typedef可用于重定义回调函数的函数指针,语法有所不同:
/** 回调函数的原始声明。1参:函数指针,即本函数所回调的函数。2参:1参函数所需的参数 */
void callbackFunc(void (*func)(char*), char* message);

可使用typedef类型重定义简化callbackFunc()函数声明中1参(函数指针)的类型:
// FuncPtrType即为重定义的类型,该类型代表所有与void xxx(char*)相匹配的函数
typedef void (*FuncPtrType)(char*);

函数指针的类型重定义后,上述回调函数的声明可写为:
void callbackFunc(FuncPtrType thisFunc, char* message);

typeid()

类型运算符,返回变量或对象的“类型”(实则返回的是type_info类的引用型对象),即RTTI运行时类型信息。后接name()可返回该类型名的char*字串。该运算符定义于标准库头文件<typeinfo>中,JUCE类库已经自包含。
cout << typeid(char).name() << endl; // 输出:“char”
int i=0; cout << typeid(i).name() << endl; // 输出:“int”

可直接比较typeid()的返回值,即比较两个type_info对象,而无需调用name()后返回并比较字串字面值。示例(添加菜单项时,判断当前LookAndFeel是否为给出的类型,如果是,则出现复选符号):
PopupMenu lookAndFeels;
lookAndFeels.addItem (201, L”默认”, true,
typeid (LookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel()));
lookAndFeels.addItem (200, L”经典”, true,
typeid (SwingLookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel()));

注意:typeid()的实参是类类型的对象时,调用name()函数后,返回的字串信息根据编译器的不同而不同。也许包含“class”,也许不包含(仅给出类型名)。

// MSVC编译环境下,cs的值为“class SwingLookAndFeel”
char* cs = typeid(LookAndFeel::getDefaultLookAndFeel()).name();

 可利用typeid()和type_info类的type_name()函数将某个类的类名返回为JUCE字符串对象:
String calssName (typeid (MyClass).type_name());

typeid()和dynamic_cast<T>强转均属于C++运行时类型信息(RTTI)方面的特性,即允许程序代码在运行时动态识别并判断当前对象的类型。注意:存在多态性时,类至少应该有一个虚函数,如此,typeid运算符才能正常运行,这一点与dynamic_cast的使用要求相一致。