C++学习(一)函数探幽

1.何为内联函数?何时用内联函数?为什么用内联函数?

(1)内联函数是指用inline关键字修饰的函数。函数的函数体放在类体内,即定义在类体内的成员函数。
(2)语句(不包括for,while,switch)简单且少,逻辑不复杂,频繁使用。
(3)使用内联函数的 目的是提高程序执行效率。(内联函数的编译代码与其他程序代码内联起来了,即编译器将使用相应的函数代码替换函数调用,对于内联代码,程序无需跳到另一位置执行代码,再跳回来),但代价是需要占用更多的内存。
宏定义和内联函数类似,都是以空间换时间,都能一定程度上加快程序的执行。

1.1内联函数和宏定义

相似性:宏定义和内联函数类似,都是以空间换时间,都能一定程度上加快程序的执行。
区别:(1)宏定义在预处理阶段由预处理器替换,内联函数是在编译时编译器执行。
(2)内联函数还有函数特性,而宏定义只是简单的字符串替换,容易出现问题。
例如:#define MULTI(x) (x*x)

在某个函数中调用MULTI(3+3),理想结果是66=36,而事实上3+33+3=15

所以宏定义的变量一般要加括号,这是一个注意点,也是一种好习惯:

#define MULTI(x) ((x)*(x))
但即使这样,还是会出问题:
当调用a=2; b= MULTI(a++); 后 理想是b=4,a=3,而事实上b=4,a加了两次a=4。
为了解决这些问题可以用内联函数替代宏定义,就不会发生这些错误。

2.何为引用?为什么使用引用传递参数?引用vs指针?何时用?

(1)引用:变量的别名,对引用操作就是直接对变量操作。
引用的声明操作:类型标识符:&引用名=变量名

int a;
char *p=&a;

(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。且通过const的使用,保证了引用传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
(4)流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

3.const 用法(修饰函数输入参数,函数返回值,const成员函数)?

(1)修饰函数输入参数?

  • 对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const引用传递”,目的是提高效率。例如将voidFunc(A a) 改为voidFunc(const A &a)。
  • 对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如voidFunc(int x) 不应该改为voidFunc(const int &x)。
    (2)修饰函数返回值?
    如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值。例如不要把函数intGetInt(void) 写成constint GetInt(void)。
    同理不要把函数AGetA(void) 写成constA GetA(void),其中A为用户自定义的数据类型。
    如果返回值不是内部数据类型,将函数AGetA(void) 改写为constA &GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。
    (3)const成员函数?
    const 成员函数的声明看起来怪怪的:const关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。
    关于Const函数的几点规则:
    a.const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
    b.const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
    c.const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
    e.然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的

4.重载?

(1)函数重载:可以有多个同名函数,因此对名称进行了重载。可以通过函数重载来设计一系列的函数-他们来完成相同的工作,且使用不同的参数列表

void print (const char *str,int width);
void print(double d,int width);
void print(long l,int width);
void print(int i,int width);
void print(const char *str);

4.函数模板和具体化?

函数模板是通用函数的描述,即用泛型来定义函数。不创建函数,只告诉编译器如何定义函数。
1>显式具体化
显式具体化也是基于函数模板的,只不过在函数模板的基础上,添加一个专门针对特定类型的、实现方式不同的具体化函数。

	template<>void swap<job>(job &a, job &b)
{
 int salary;
 salary = a.salary;
 a.salary = b.salary;
 b.salary = salary;
}

如上所示,该具体化函数的实现与模板并不一致,编译器解析函数调用时会选择最匹配的函数定义。
2>定义同名常规函数

void swap(job &a, job &b)
{
 int salary;
 salary = a.salary;
 a.salary = b.salary;
 b.salary = salary;
}

由于编译器在重载解析时,会选择最匹配函数定义,所以在调用swap(jobA, jobB)时,编译器会选择void swap(job &a, job &b)函数定义,而屏蔽了模板函数。

同时,模板函数也可以重载,其操作与常规函数一致。

template <class T> void swap(T &a, T &b);
template <class T> void swap(T &a, T &b, T &c);
template <typename T> void swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template <typename T> void swap(T &a, T &b, T &c)
{
T temp;
temp = a;
a = b;
b = c;
c = temp;
}

上面主要说的是函数模板的具体化,下面说下模板实例化。
函数模板:

#define MAXNAME 128
struct job
{
char name[MAXNAME]:
int salary;
};

template<class T>
void swap(T &a, T &b )
{
T temp;
 temp = a;
 a = b;
 b = temp;
};

template void swap<int>(int &a, int & b);  //显式实例化,只需声明

template<> void swap<job>(job &a, job &b)   //显式具体化(上面已经讲过,注意与实例化区分开,必须有定义)
{
  int salary:
 salary = a.salary:
  a.salary = b.salary;
  b.salary = salary;
};//explicite specialization.

类模板:
template <class T>
class Arrary
{
private:
  T* ar;
int l;
...
};//template class declaration.

template class Array<int>;   //explicit instantiation. 显式实例化

template<> class Array<job>
{
private:
  job* ar;
 int l;
};//expicit specialization.   

显式具体化,类定义体可以不同于类模板Array
相应的,隐式实例化指的是:在使用模板之前,编译器不生成模板的声明和定义实例。只有当使用模板时,编译器才根据模板定义生成相应类型的实例。如:

int i=0, j=1;
swap(i, j);  //编译器根据参数i,j的类型隐式地生成swap<int>(int &a, int &b)的函数定义。
Array<int> arVal;//编译器根据类型参数隐式地生成Array<int>类声明和类函数定义。

显式实例化:
当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例。如前面显
示实例化(explicit instantiation)模板函数和模板类。其格式为:

template typename function<typename>(argulist);
template class classname<typename>;

显式实例化只需声明,不需要重新定义。编译器根据模板实现实例声明和实例定义。
显示具体化:
对于某些特殊类型,可能不适合模板实现,需要重新定义实现,此时可以使用显示具体化(explicite specialization)。显示实例化需重新定义。格式为:

template<> typename function<typename>(argu_list){...};
template<> class classname<typename>{...};

综上:

template<> void swap<job>(job &a, job &b) {……};是函数模板的显式具体化,意思是job类型不适用于函数模板swap的定义,因此通过这个显式具体化重新定义;也可简写作template<> void swap(job &a, job &b);
template void swap<job>(job &a, job &b);是函数模板的一个显式实例化,只需声明,编译器遇到这种显式实例化,会根据原模板的定义及该声明直接生成一个实例函数,该函数仅接受job型。否则编译器遇到模板的使用时才会隐式的生成相应的实例函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值