C++初学者指南 第八篇(7)

来源:互联网 发布:淘宝购物券怎么用 编辑:程序博客网 时间:2024/04/30 05:11

必备技能8.6:内联函数

在我们继续探讨类之前,有必要先对一个很重要的题外话进行讨论一下。那就是内联函数。尽管它并不属于面向对象的编程范畴,但它是C++中一个非常有用的特性,也是经常会在类的定义中被用到的一个特性。一个内联函数会在引用它的地方被展开,而不是像普通函数那样是被调用。有两种方式可以创建一个内联函数。其一就是使用inline修饰符。

例如,想要创建一个名称为f,返回值为一个int类型的,不需要参数的函数,可以采用如下的方式来声明它:

inline int f()

{

    //...

}

其中inline修饰符是要放置在声明函数的其它要素之前的。

内联函数的存在是出于效率的考虑。每一次进行函数调用的时候,计算机必须执行一些列的指令来完成函数的调用。其中就包括参数的入栈。在很多情况下,完成这些操作需要多个CPU周期。然而,当一个函数被以内联的方式展开的时候,就不会存在这样的开销。因此,程序运行的总速度也会提高。但是,如果内联函数中的代码非常多,那么程序的总大小也将会变得很大。正式由于这样的原因,最好的内联函数就是那些非常短小的函数。大多数的大型函数不应该是内联函数,而应该是作为普通的函数。

下面的程序就展示了内联函数的用法:

//内联函数的示例 #include <iostream>using namespace std; class c1{    int i; // 缺省为私有的数据成员public:    int get_i();    void put_i(int j);    }; inline int c1::get_i(){    return i;} inline void c1::put_i(int j){    i = j;} int main(){    c1 s;    s.put_i(10);    cout << s.get_i();        return 0;}

有一个技术点必需明确:inline只是一种要求,而不是一种命令。也就是说inline修饰符只是要求编译器生成内联的代码。但是在很多情况下,编译器是不会按照inline的要求来生成内联代码的。下面列举了一些这样的情况:

如果一个函数含有循环,switch或者goto语句,有些编译器则不会生成内联代码。

递归函数不能作为内联函数

含有静态变量的函数通常是不允许作为内联函数的。

请记住:内联的限制要求和编译器有密切的关系。因此我们最好查阅一下自己使用的编译器的文档,以确定其对内联函数有那些具体的要求。

在类的内部创建内联函数

第二种创建内联函数的方法就是在定义类的代码中来定义函数的实现编码。任何在类的定义中定义的函数都会被自动地被认为是内联函数。此时就不需要在函数的声明前面使用关键字inline了。例如,前面的程序可以重写为:

//内联函数的示例 #include <iostream>using namespace std; class c1{    int i; // 缺省为私有的数据成员public:    int get_i() { return i; };// 在类的定义中定义函数    void put_i(int j) { i = j; };    };  int main(){    c1 s;    s.put_i(10);    cout << s.get_i();        return 0;}


请注意上面程序中函数代码的组织方式。对于那些非常简短的函数,上面的代码组织方式反映出了典型的C++风格。然而,我们也可以这样编写代码:

class c1{    int i; // 缺省为私有的数据成员public:int get_i() {     return i; };// 在类的定义中定义函数void put_i(int j) {     i = j; };    };

一些比较短小的函数,例如上面程序中的这些函数,通常都会在类的定义中来定义。在使用类的时候,使用内联函数是一种非常常见的现象。这是因为在类中通常需要提供一个公有的函数来提供对私有数据的访问。这种函数被称为访问函数。由于大多数C++程序员都会在类中定义访问函数和其它一些短小的函数,我们在本书后面的示例程序中也会采用这种传统。这也是我们应该使用的一种方式。

下面的程序中,我们重新编写了Vehicle类。其构造函数和析构函数,以及range()函数都是在类中定义的。变量passengersfuelcapmpg都被声明成了私有的数据。我们为其增加了访问函数来获取他们的值。

//内联的构造函数,析构函数和range()函数 #include <iostream>using namespace std; //声明Vehicle类class Vehicle{    //私有数据    int passengers;    int fuelcap;    int mpg;    public:    //构造函数    Vehicle(int p, int f, int m )    {        passengers = p;        fuelcap =f;        mpg = m;    }        //计算并返回最大行程    int range()    {        return mpg * fuelcap;    }        //访问函数    int get_passengers() { return passengers ; }    int get_fuelcap() { return fuelcap; }    int get_mpg() {return mpg; }}; int main(){    //给Vehicle的构造函数传递参数    Vehicle minivan(7,16,21);    Vehicle sportscar(2,14,12);        int range1, range2;        //计算装满油后最大能行驶的里程数    range1 = minivan.range();    range2 = sportscar.range();        cout << "Minivan can carry " << minivan.get_passengers()          << " withe a range of " << range1 << "\n";    cout << "sportscar can carry " << sportscar.get_passengers()          << " withe a range of " << range2 << "\n";                return 0;}


由于成员变量现在都是私有的,我们就必须在main()函数中使用访问函数get_passengers()来获取一辆车的载客人数。

练习:

1. inline 是用来做什么用的?

2. 是否可以在类的声明中定义内联函数?

3. 什么是访问函数?

4. 

 

专家答疑

问:是否可以在一个类中声明另外的一个类? 也就是说类的声明是否可以嵌套?

答:是的。在一个类中定义另外的一个类是可以的,这样就是创建了一个嵌套类。由于类的声明实际上定义了一个作用范围,因此嵌套的类只有在该类的范围内才是有效的。坦白来讲,由于C++的其它一些丰富特性和灵活性,例如后面我们会讨论到的继承性,需要创建嵌套类的情况实际上不存在。