Effective C++条款37

不要重复定义virtual 函数中的参数缺省值,如果重复定义,会出现程序调用过程超乎常理的结果。

大家看如下代码:

#include<iostream>
using namespace std;

class Shape
{
public:
    enum ShapeColor{Red,Green,Blue};
    virtual void Drew(ShapeColor color=Red)
    {
        if (color == Red)
            cout << "Red" << endl;
        else if (color == Blue)
            cout << "Blue" <<  endl;
        else
            cout << "Green" << endl;
    }

};

class Rectangle :public Shape
{
public:
    virtual void Drew(ShapeColor color=Green)
    {
        if (color == Red)
            cout << "Red" << endl;
        else if (color == Blue)
            cout << "Blue" << endl;
        else
            cout << "Green" << endl;
    }
};

int main()
{
    Shape *s = new Rectangle();
    s->Drew();//调用结果打印Red,而不是Green。
    return 0;
}

我们肯定为结果的出乎意料而苦恼,想不通为什么会出现这种现象。在这里我做一个简单地解释。首先,大家要明白静态绑定和动态绑定的区别。

我们的virtual函数是动态绑定的调用过程,它的调用决策者是实际指向的对象。而我们函数中缺省值的选定却是静态绑定,它的决策者是当前正在调用的对象类型。

我们看上面的例子,s指针是shape类的,实际指向Rectangle类的对象,调用Drew函数时由于Drew是virtual函数,所以调用Rectangle类中的Drew函数,可是选择的函数参数缺省值却是Shape类的。

时间: 2024-10-11 17:20:03

Effective C++条款37的相关文章

Effective C++:条款37:绝不重新定义继承而来的缺省参数值

由于重新定义继承而来的non-virtual函数是不正确的(见上一个条款),所以这个条款就将问题局限于:绝不重新定义继承一个带有缺省参数值的virtual函数. (一) virtual函数是动态绑定的,而缺省参数却是静态绑定. 对象的所谓静态类型,是它在程序中被声明时所采用的类型. 你可能会在"调用一个定义于derived class 内的virtual函数"的同时,却使用了base class为它所指定的缺省参数值. (二) 为什么继承而来的virtual函数的缺省参数值不能被重新定

Effective C++:条款37:绝不又一次定义继承而来的缺省參数值

因为又一次定义继承而来的non-virtual函数是不对的(见上一个条款),所以这个条款就将问题局限于:绝不又一次定义继承一个带有缺省參数值的virtual函数. (一) virtual函数是动态绑定的,而缺省參数却是静态绑定. 对象的所谓静态类型,是它在程序中被声明时所採用的类型. 你可能会在"调用一个定义于derived class 内的virtual函数"的同一时候,却使用了base class为它所指定的缺省參数值. (二) 为什么继承而来的virtual函数的缺省參数值不能被

More Effective C++ 条款35 让自己习惯于标准C++ 语言

(由于本书出版于1996年,因此当时的新特性现在来说可能已经习以为常,但现在重新了解反而会起到了解C++变迁的作用) 1. 1990年后C++的重要改变 1). 增加了新的语言特性:RTTI,namespaces,bool,关键词mutable和explicit,enums作为重载函数之自变量所引发的类型晋升转换,以及"在class 定义区内直接为整数型(intergral) const static class members设定初值"的能力. 2). 扩充了Templates的特性

effective c++ 条款4 make sure that objects are initialized before they are used

1 c++ 类的数据成员的初始化发生在构造函数前 class InitialData { public: int data1; int data2; InitialData(int a, int b) { data1 = a: //this is assignment data2 = b; //this is assignment } /* InitialData(int a, int b):data1(a),data2(b) //this is initial {} */ } 2 不同cpp文

More Effective C++ 条款34 如何在一个程序中结合C++和C

1. C++和C混合使用的前提之一就是编译器产生兼容的目标文件(.lib和.dll等).所谓"兼容",指的是编译器在"预编译器相依的特性上"一致,如int和double大小,参数压栈机制等,只有在这个基础上才能讨论结合使用C++和C模块的问题. 2. 在1的基础上,要结合使用C++和C的模块,主要有以下几点需要注意: 1). name mangling(名称重整) Name mangling是C++用于支持函数重载的机制,它对重载的函数名称进行一定改变,使得每个函数

Effective C++ 条款3 尽可能用const

1. const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体.用const修饰指针,如果const出现在*之前,表明指针不能更改所指向的对象的内容,如果const出现在*之后,表明指针只能指向同一块内存.另外int const*p和const int*p含义相同.如果对象成员有普通指针,那么构造该类的一个const对象时,const修饰使得该指针只能指向同一块内存,但指针指向的内容可以改变. 2. 将某些东西声明为const可以帮助编译器侦测出错误用法. 3. 编译器强制实

effective c++ 条款13 use object to manage resources.

请求的系统资源需要最终还回系统,为了避免遗忘返还这个动作,可以利用析构函数在object销毁时自动调用的特点来实现. 简单说就是用object来管理资源. 以内存资源为例 class Investment {}; Investment* creatInvestment(){...} // factory function to produce investment object void main() { Investment* pInv = creatInvestment();//call t

effective c++ 条款3 use const whereever you can

1 const 传达的意思应该是这个变量是常量不能更改 2 const 在 * 左边表示数据是const,在右边表示指针是const // char greeting[] = "hello"; char* p = greeting; //const *: const data //* const: const pointer char const *p1 = greeting; // const data char * const p2 = greeting; // const poi

effective c++ 条款18 make interface easy to use correctly and hard to use incorrectly

举一个容易犯错的例子 class Date { private: int month; int day; int year; public: Date(int month,int day,int year) { this->month = month; ... } } //wrong example Date date(30,3,1995);//should be 3,30 Date date(2,30,1995);//should be 3,30 使用类型可避免这个问题 class Month