首页 > 代码库 > C++必知必会(2)

C++必知必会(2)

17.处理函数和数组声明

指向函数的指针声明与指向数组的指针声明很容易混淆,主要原因在于函数和数组修饰符的优先级比指针修饰符的优先级高,因此通常需要使用圆括号。

int *f1();                            //一个返回值为int* 的函数

int (*fp1)();                 //一个指针,指向一个返回值为int的函数

 

const int N =12;        

int* a1[N];                  //一个具有N个int *元素的数组

int (*ap1)[N];             //一个指针,指向一个具有N个int元素的数组

 

int *(*fp3)();               //一个指针,指向一个返回值为int*的函数

注意,参数和返回值都会影响函数或函数指针的类型。

char* (*fp4)(int,int);

char* (*fp5)(short,short)= 0;

fp4 = fp5;      //错误!类型不匹配

 

当函数和数组修饰符出现在同一声明中时,事情的复杂性会变得难以估计。如下:

int (*)()afp1[N];   //语法错误!

在以上错误的声明中,企图声明一个函数指针数组。但函数修饰符()的出现表示到了声明的末尾,而后附加的afp1则表示开始出现了一个语法错误。

       函数指针数组的正确声明方式,是将数组名字和简单的函数指针声明放在一起。

int (*afp2[N])();   //一个具有N个元素的数组,其元素类型是指向返回值为int的函数指针。

条款18函数对象

与智能指针一样,函数对象时一个普通的类对象。智能指针重载->和*操作符来模仿指针的行为;而函数对象类型则重载函数调用操作符(),来创建类似函数指针的东西。

class A{

       public:

int operator()();

}

A a;

a();  //可以像调用函数一样调用函数对象。

条款19 Command模式与好莱坞法则

命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。

好莱坞法则:不要call我们,我们会call

条款20 STL函数对象

STL中诸如sort,find_if等模板函数允许有第三个参数(sort中是一个比较函数指针或比较函数对象,find_if是一个判断函数指针或一个判断函数对象),这个参数可以是函数指针,也可以是函数对象。

用函数对象叫函数指针的好处是比较操作可以被内联,但是用函数指针则不允许内联。原因在于,当一个sort或find_if函数模板实例化时,编译器知道比较函数对象的类型,从而比较函数对象的operator ()将被调用,接着使他内联函数,而函数指针无法做到。

条款21重载和重写并不相同

条款22 Template Method模式

模板方法模式:模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

通常来说,Template Method被实现为一个公有非虚函数,它调用被保护的虚函数。派生类必须接受它继承的非虚基类所指明的全部实现,同时还可以通过重写该共有函数所调用的被保护的虚函数,以有限的方式来定制其行为。

       class App{

       public:

              virtual ~App();

void startup()

{

       initialize();

if( !validate())

              altInit();

}

protected:

       virtualbool validate() const = 0;

       virtualvoid alInit();

private:

       voidinitialize();

};

class MyApp : public App{

       public:

       private:

              boolvalidate() const;

              voidaltInit();

};

Template Method是好莱坞法则的例子。startup函数的整体流程由基类决定,客户通过基类的接口来调用startup,因此派生类设计者不知道validate或altInit何时会被调用。但他们知道当这两个方法被调用时,它们各自应该做什么。

条款23 名字空间

条款24成员函数查找

步骤1.编译器检查查找函数的名字

步骤2.从可用候选者中选择最佳匹配函数

步骤3.检查是否具有访问该匹配函数的权限

条款25实参相依的查找

实参相依的查找(ADL)思想:当查找一个函数调用表达式中的函数名字时,编译器也会到“包含函数调用实参的类型”的名字空间中检查。考虑如下代码:

namepaceorg_semantics{

       class X{…};

void f(const X&);

void g(X*);

X operator+ (const X&, const X&);

class String{…};

std::ostream operator << (std::ostream &, const String&);

}

//…
       int g(org_semantice::X *);

       voidaFunc()

{

              org_semantics::Xa;

              f(a);                            //调用org_semantics::f

              g(&a);                  //错误!调用歧义

              a= a+a;               //调用org_semantics::operator+

}

普通的查找是不会发现函数org_semantice::f的,因为它被嵌套在一个名字空间内,并且对f的使用需要以该名字空间的名字加以限定。然而,由于实参a的类型被定义org_semantics名字空间中,因此,编译器也会到该名字空间中检查候选函数。

但对函数g的调用就会产生歧义。