接上节的引用知识点,我们继续来看看内联函数、构造函数和析构函数。
一.内联函数
内联函数的标志是inline,与其对比的是宏函数,不知道大家有没有听过这个概念,比如我们定义一个宏:
#define ADD(x,y) ((x)+(y))
类似上面这行代码的宏就是宏函数了,他类比于宏来说,没有来性的严格限制,也不需要频繁的像函数一样建立栈帧,大大提高了程序的效率。
然而内联函数,也跟宏函数差不多,看下面代码:
inline int ADD(int x,int y)
{
return x + y;
}
上面的函数跟普通的add函数相比,只是多了一个inline的区别,但是具体体现在哪里呢,我们来看看反汇编。
很明显,我们可以看到,这里并没有用函数去压栈帧,而是直接展开了,我们换成不是内联函数的形式看看:
很明显,这里直接call进了函数里,函数进行了压栈,占用了一定的空间。
所以我们可以看到,应用内联函数,我们可以减少函数压栈的空间,从而提高代码的效率。
如果是这样的话,我们岂不是全部使用内联函数就行了?我们来看:
我们看到,这种情况下,函数就不会直接展开了,因为这是一个无限递归的函数,如果直接展开的话,反汇编会非常的多,导致代码膨胀,得不尝失,所以编译器在这里会进行检测,如果函数中代码超过了大概7行,那么就会自动屏蔽inline,当成正常函数使用。
二.构造函数
在c++类里面,有六个默认成员函数,而构造函数就是其中的一种。
构造函数是特殊的成员函数,它并不开空间,主要是初始化的工作。它有以下几点需要注意:
1.函数名要与类名相同。
2.无返回值,不需要写void。
3.对象实例化时会自动调用对应的构造函数。
4.构造函数可以函数重载。
我们可以看一下例子:
class A
{
public:
A(int x=2, int y=3)
{
_a = x;
_b = y;
}
void Print()
{
cout << _a << " " << _b << endl;
}
private:
int _a;
int _b;
};
A aa;
aa.Print();
我们来看一下运行结果:
可以看见我们并不需要调用构造函数,编译器会直接去调用,如果你自己没有在类里面写构造函数,那么编译器会自动生成一个,但是如果你自己写了的话,那么编译器就不会再自动生成,那么内置类型的成员就不会自己处理,但是如果你是自定义类型的成员,那么编译器会去调用自定义成员的构造函数。在上面我们可以看到,构造函数也可以是缺省的,这样有助于我们初始化。
总之,构造函数一般来说都要我们自己实现,决定初始化方式,成员变量如果全是构造函数,那么就可以考虑不写构造函数。
三.析构函数
析构函数也是六大默认成员函数的一种,他和构造函数一样,也是特殊的成员函数,但是跟构造函数还是有些不一样:
1.要在类名前加~。
2.无参数无返回值。
3.一个类只有一个析构函数。若未显示定义,那么会自动生成默认的析构函数。
4.对象生命周期结束时,会自动调用析构函数。
我们验证一下:
class A
{
public:
A(int x=2, int y=3)
{
_a = x;
_b = y;
}
void Print()
{
cout << _a << " " << _b << endl;
}
A(A& a)
{
_a = a._a;
_b = a._b;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
int _b;
};
然后主函数与上面一样,我们来看测试结果:
可以看到,我们没有使用析构函数,它自己内部去调用了。这对于那种需要自己释放空间的类型有着不错的效果。