【程序员面试宝典】RTTI与运算符重载

❀RTTI

        RTTI(Run-Time Type Identification)是面向对象程序设计中一种重要的技术。现行的C++标准对RTTI已经有了明确的支持。不过在某些情况下出于特殊的开发需要,我们需要自己编码来实现。和很多其他语言一样,C++是一种静态类型语言。其数据类型是在编译期就确定的不能在运行时更改。然而由于面向对象程序设计中多态性的要求,C++中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致。有时我们需要将一个多态指针转换为其实际指向对象的类型,就需要知道运行时的类型信息,这就产生了运行时类型识别的要求

        C++提供了两个关键字typeiddynamic_cast,一个类type_info来支持RTTI。
        dynamic_cast操作符:它允许在运行时刻进行类型转换,从而使程序能够在一个类层次结构安全地转换类型。dynamic_cast提供了两种转换方式,把基类指针转换成派生类指针,或者把指向基类的左值转换成派生类的引用

void company::payroll(employee *pe) {  
//对指针转换失败,dynamic_cast返回NULL  
if(programmer *pm=dynamic_cast(pe)){  
pm->bonus();   
}  
}  
  
void company::payroll(employee &re) {  
try{  
//对引用转换失败的话,则会以抛出异常来报告错误  
programmer &rm=dynamic_cast(re);  
pm->bonus();  
}  
catch(std::bad_cast){  
}  
} 

        这里bonus是programmer的成员函数,基类employee不具备这个特性。所以我们必须使用安全的由基类到派生类类型转换,识别出programmer指针。

     动态映射dynamic_cast<目标*><源指针>,先恢复源指针的RTTI信息,再取目标的RTTI信息,比较两者是否相同,或者是目标类型的基类;由于它需要检查一长串基类列表,故动态映射的开销比typeid要大。

second *p2=dynamic_cast<second *><p>;//p是基类指针,把基类指针p通过这种方式变成其派生类的指针。

或者second *p2=dynamic_cast<p>;

         typeid操作符:它指出指针或引用指向的对象的实际派生类型。

employee* pe=new manager;  
typeid(*pe)==typeid(manager) //true 

        typeid可以用于作用于各种类型名,对象和内置基本数据类型的实例、指针或者引用,当作用于指针和引用将返回它实际指向对象的类型信息。typeid的返回是type_info类型。
        type_info类:这个类的确切定义是与编译器实现相关的,下面是《C++ Primer》中给出的定义(参考资料[2]中谈到编译器必须提供的最小信息量):

class type_info {  
private:  
type_info(const type_info&);  
type_info& operator=( const type_info& );  
public:  
virtual ~type_info();  
int operator==( const type_info& ) const;  
int operator!=( const type_info& ) const;  
const char* name() const;  
};  

运行类型识别RTTI使用需要注意的问题
(1)在分布式系统中,不适用RTTI的一个合理的解释 是RTTI行为不可预期及缺乏扩展性
(2)用typeid()返回一个typeinfo对象,也可以用于内部类型,当用用于非多态类型时没有虚函数,用typeid返回的将是基类地址;
(3)不能对void指针进行映射;
(4)如果p是指针,typeid(*p)返回p所指向的派生类类型,typeid(p)返回基类类型;如果r是引用,typeid(r)返回派生类类型,typeid(&r)返回基类类型;
(5)C++里面的typeid运算符返回值是 type_info常量对象的引用


❀运算符重载

        所谓重载,就是重新赋予新的含义,函数重载就是对一个已有的函数赋予新的含义,使之实现新功能。
        运算符的重载主要存在两种形式,一种是作为类的成员函数进行使用,另一种则是作为类的友元函数进行使用。
        运算符的重载的形式:

返回类型 operator 运算符符号(参数说明)  
{      
    //函数体的内部实现  
}  

        例如,能否用“+”号进行两个复数的相加,在C++中不能在程序中直接用运算符“+”对复数进行相加运算,用户必须自己设法实现复数相加。
        运算符重载运算符的运算规则
        (1)运算符重载函数也是函数,重载的运算符不会改变运算符的优先级、结合型和参数的个数。
        (2)重载运算符不能违反语言的语法规则。
        (3)赋值运算符除外,重载运算符可由派生类继承下去。
        (4)重载运算符不能使用默认参数。
        (5)运算符=、()、[]和->等操作符必须定义为类的成员函数,将这些操作符定义为友元函数将在编译时标记为错误。
        (6)C++中不能重载的运算符只有5个:
        . (成员访问运算符)
        .* (成员指针访问运算符)
        ∷ (域运算符)
        sizeof(长度运算符)
        ?: (条件运算符)

        因为前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具重载的特征。

        (7)友元运算符的参数规则与类成员运算符的参数规则不同,一元运算符必须显示地声明一个参数,二元运算符必须显示地声明两个参数。类成员运算符重载时,参数中隐含了一个this指针。(另外,C++规定,有的运算符(如赋值运算符、下标运算符、函数调用运算符)必须定义为类的成员函数,有的运算符则不能定义为类的成员函数(如流输入“>>”和流输出“<<”运算符、类型转换运算符))。
        重载为类的成员函数时,参数个数=原操作数个数-1(后置++、--除外),它可以通过this指针自由地访问本类的数据成员,可以少写一个函数的参数,但必须要求运算表达式的第一个参数(即运算符左侧的操作数)是一个类对象。
        重载为类的友元函数时,参数个数 = 原操作数个数,且至少应该有一个自定义类型的形参。
        定义一个重载运算符函数参数表中参数的决定个数,取决于两个主要因素operator@
        1)运算符是一元的(一个参数)还是二元的(两个参数)
        2)运算符被定义为全局函数:对于一元运算符,一个参数;对于二元运算符是两个参数
        3)运算符是成员函数:对于一元运算符没有参数,对于二元元素符是一个参数


        如何重载增量运算符++和--
        运算符++和—-有前置和后置两种形式,要使用operator++( )或operator--( )来重载前置运算符,使用operator++(int)或operator--(int)来重载后置运算符,调用时,参数int被传递给值0。

        重载流输入运算符和流输出运算符
        istream 类的对象cin;
        ostream类的对象cout;
        如果想直接用“<<”和“>>”输出和输入自己声明的类型的数据,必须对它们重载,对“<<”和“>>”重载的函数形式如下:

istream & operator >> (istream &,自定义类 &);  
ostream & operator << (ostream &,自定义类 &);  

        重载运算符“>>”的函数的第一个参数和函数的类型都必须是istream&类型,第二个参数是要进行输入操作的类。
        重载“<<”的函数的第一个参数和函数的类型都必须是ostream&类型,第二个参数是要进行输出操作的类。
        只能将重载“>>”和“<<”的函数作为 友元函数或普通的函数,而不能将它们定义为成员函数。

friend ostream & operator <<(ostream & out, const classM & A);//在类classM中声明友元函数

ostream & operator <<(ostream & out, const classM & A)

{

out<<A.num<<endl;

return out;

}//在类外写函数体

调用:cout<<A;//重载<<运算符,输出对象A的num属性值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值