1.内联函数
为提高程序运行速度,不必在调用函数时跳到另一个位置执行代码再跳回来。采用内联函数,内联函数的编译代码与其他程序代码“内联”起来,即编译器将使用相应的函数代码替换函数调用。速度提高,但内存开销变大。
注意在函数声明之前+inline,在函数定义前+inline。通常做法是省略原型,将整个定义放在本应提供原型的地方。(内联不能使用递归,有些编译器可能没有这种特性)。一般来说冗长的代码段函数不大适宜用作内联函数。
注意c语言中的#define宏定义是通过文本替换(而不是传递参数)实现的,如#define SQUARE(X) X*X
若提供5,结果是5*5.提供4.5+7.5,结果是4.5+7.5*4.5+7.5.若提供c++,结果是c++*c++.
2.引用变量
引用是已定义的变量的别名,主要用途是作函数的形参。将引用变量作为参数,函数将使用原始数据而不是其副本。&除了取地址符,也用来声明引用。如int rats;int &redents=rats;
注意这是将redents作为rats的别名。此时&作为类型标识符的一部分。Int &代表是指向int的引用。上述引用允许将rats和rodents互换,它们指向相同的值和内存单元。即cout<<rats<<rodents; 是相同的一个变量。注意必须在声明引用时将其初始化。指针可以先声明再赋值。
引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来就将一直效忠于它。即int &rodents=rats;与 int *const pr=&rats;类似。如果通过赋值给rodent一个新值(新变量),那么rodent和rat的值变成了新值,但它们的地址还是原来的地址,与新值的地址并不一样。又或者引用绑定在一个指针上,即使指针变化指向其他值,引用指向的还是原值。
3.将引用用作函数参数
引用被当作函数参数时,函数中的变量名成为调用程序中变量的别名。按引用传递允许被调用函数可以访问调用函数中的变量。按值传递是两个变量,两个名称。按引用传递是一个变量两个名称。引用作形参,调用时直接给变量,相当于把形参初始化为传递的实参,指针做形参,调用时用&给出地址。当意图让函数使用传递给它的信息而不需修改时,则应使用传值,但若要想用引用,那么应该使用const限定,如double( const double &ra);另外当数据比较大时,引用参数将比较有用。注意传递引用的限制更加严格,如果ra是一个变量的别名则实参应是该变量。(x+3就不行)
在当前情况下,实参与引用参数不匹配,仅当参数为const引用时,c++将生成临时变量。即对于形参是const引用的c++函数,如果实参不匹配,则其行为类似按值传递,为确保原始数据不被修改,将使用临时变量来存储值。如果函数调用的参数不是左值(变量,数组元素,结构成员,引用和解除引用的指针,非左值包括字面常量,用引号括起来的字符串除外,它们由其地址表示)或者与相应的const引用参数类型不匹配的,则c++将创建类型正确的匿名变量。将函数调用的参数的值传给该匿名变量并让参数来引用该变量。
4.将引用用于结构
函数原型还是一样,如void set_pc (free_throws &ft); 如果不希望函数修改传入的结构可使用const。void display(const free_throw &ft); 初始化结构时,如果指定的初始值比成员少,余下的成员将被设置为0. 如果函数返回的是引用那么可以进行这样的赋值,accumulate(dup,five)=four;传统的返回机制与按值传递函数类似,计算return后面的表达式并将结果返回给调用函数。也就是说这个值被复制到一个临时位置,而调用程序将使用这个值。如果函数返回一个结构,将把整个结构复制到一个临时位置,再将这个拷贝复制给dup(变量)。但在返回引用时,将直接把返回值复制到dup。
注意要避免返回指向函数内部临时变量的引用,最简单的方法则是返回一个作为参数传递给函数的引用,作为参数的引用将指向调用函数使用的数据。另一种方法是使用new来分配新的存储空间。使用引用可以完成类似工作如
const free_throw & clone(free_throw & ft)
{
free_throws *pt; *pt=ft; return *pt;
}
5.将引用用于类对象
将类对象传递给函数时通常做法是使用引用,让函数将类string,ostream,istream,ofstream和ifstream等类的对象作为参数。注意string类允许使用char *的c-风格字符串来初始化string对象。
类型为const引用的形参的一个属性是:假设实参的类型与引用参数类型不匹配但可被转化为引用类型,程序将创建一个正确类型的临时变量,使用转换后的实参值来初始化它,然后传递一个指向该临时变量的引用。可以将实参char *(如引号括起来的字符串字面量,空字符结尾的char数组或指向char的指针变量),const char*传递给形参const string&。坚决不能返回局部变量的引用!!!
6.对象,继承和引用
使得能够将特性从一个类传递给另一个类的语言特性叫做继承。派生类对象可以使用基类特性,如方法。基类引用可以指向派生类对象,而无需进行强制转换。即可以定义一个接受基类引用作为参数的函数,调用该函数时可以将基类对象,和派生类对象作为参数。
格式化输出:setf(ios_base::fixed)将对象置于使用定点表示法,即原始格式输出,不适用科学计数法。,setf(ios_base::showpoint)显示小数点模式,precision()显示多少位小数.width()设置下一次输出操作的字段宽度,只在下一个值有效然后将恢复到默认设置。默认字段宽度为0,意味着刚好放下显示的内容。可以使用
ios_base::fmtflags initial; //存储有效的格式化操作
initial=os.setf(ios_base::fixed); … //操作
os.setf(initial);//重新调用所有有效操作。
7.默认参数
可以在函数原型中设置默认值,如char * left(const char * str, int n=1);对于代参数列表的函数,必须从右向左添加默认值,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。实参按从左到右的顺序依次被赋给相应的形参而不能跳过任何参数。因此
Beeps=harpo(3, ,8)是不允许的。默认参数可以实现以不同数目的参数调用同一个函数。
8.函数重载
函数多态(函数重载)能够使用多个同名的函数,它们完成相同的工作但是用不同的参数列表。C++使用上下文来确定要使用的重载函数版本。函数重载的关键是函数的参数列表——函数特征标。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则其特征标相同。C++允许定义名称相同的函数,条件是它们的特征标不同。从编译器角度而言,把类型引用和类型本身视为同一个特征标。注意,是特征标,而不是函数类型使得可以对函数进行重载。如下面两个声明是互斥的
Long gronk(int n,float m); double gronk(int n,float m);仅仅如此是不允许重载的。
函数类型可以不同,但特征标必须不同。
小逻辑:返回正数的前几位代码段设计思路:n/=10;每除以10就可以去掉一位。知道有几位要返回几位代码完整如:
ct=digits-ct; while(ct--){num/=10;} return num;
9.函数模板
函数模板使用泛型来定义函数,其中的泛型可用具体类型替换,通过将类型作为参数传递给模板,使编译器生成该类型的函数。函数模板:
Template<typename hehehe>
Void swap(hehehe &a, hehehe &b)
{
Hehehe temp;
temp=a; a=b; b=temp;
} 也可以使用class代替typename。调用时直接使用swap(x,y)。注意最常见的是将模板放在头文件中,并且在需要使用模板的文件中包含头文件。
重载的模板:
被重载的模板的函数特征标必须不同。注意在模板函数的参数中,可以存在具体类型,不必全是模板类型。
显示具体化:
当想交换两个结构中的部分成员,而不是简单交换两个结构的情况下,以上模板代码将不再适用,此时可以进行一个具体化函数定义,即显示具体化。
第三代具体化规则:
对于给定的函数名,可以有非模板函数、模板函数和显示具体化模板函数以及它们的重载版本。
显示具体化的原型和定义以template<>打头,并通过名称来指定类型。
匹配时,显示具体化优先于常规模板,而非模板函数优先于具体化和常规模板。
交换结构部分成员的三种原型
Void swap(job &,job &);
Template<typename T>
Void swap(T &,T&);
Template<>
Void swap<job>(job &,job &);
实例化和具体化:
模板本身只是一个函数定义的方案,只有在调用时才生成模板实例。Swap(i,j)是一个隐式实例化,还可以显式实例化,swap<int>(),声明时template void swap<int>(int,int);编译器将使用swap模板生成一个使用int类型的实例。记住与显示具体化之间的区分:
Template<> void swap(int &,int&) ;或者template<>void <int>(int &,int&);
隐式实例化、显示实例化和显示具体化统称为具体化。以下代码段总结了三种异同。
Template <class T>
Void swap(T&,T&);
Template<>
Void swap<job>(job&,job&);//显示具体化,用另一个模板函数来实现结构成员的交换。
Int main()
{
Template void swap<char>(char&,char&);//显示实例化声明,一般在main内部
Short a,b;
Swap(a,b);//通用模板隐式实例化
Job n,m;
Swap(n,m);//使用显示具体化模板函数
Char g,h;
Swap(g,h);使用显示实例化一个char型的函数版本。
}
编译器选择使用哪个函数版本的原则:
1.创建候选函数列表,其中包含与被调用函数名称相同的函数和模板函数(按名匹配)
2.使用候选函数列表创建可行函数列表,这些都是参数数目正确的函数,为此有一个隐式转换的序列,其中包括实参类型与相应的形参类型完全匹配的情况。
3.确定是否有最佳的可行函数。如果没有则函数调用出错。
在确定最佳时原则:
1.完全匹配,但常规函数优先于模板
2.提升转换(char和short自动转换为int,float自动转化为double)
3.标准转换(int转换为char,long转换为double)
4.用户定义的转换,如类声明中定义的转换。
当完全匹配不止一个时:
进行完全匹配时,c++允许一些“无关紧要的转换”,当完全匹配不止一个时,编译器将无法完成重载解析过程,如果没有最佳函数,那么会生成ambiguous的错误。然而有时候两个函数都是完全匹配,还是可以完成重载解析。首先指向非const数据的指针和引用优先与非const指针和引用参数匹配。但是单纯的const变量或者非const变量在参数匹配上并无先后之分。其次,非模板函数的匹配优先于模板函数(包括显示具体化)。并且当都是模板函数的情况下,那么较具体的模板函数优先。即显示具体化将优于隐式模板实例。
decltype关键字:
decltype (expression) var;为确定类型,编译器必须遍历一个核对表。
1.如果expression是一个没有括号括起来的标识符,则var的类型与该标识符的类型相同,包括const限定符。
2.如果expression是一个函数调用,则var的类型与函数的返回类型相同(通过查看原型得知)。
3.如果expression是一个左值,则var指向其类型的引用。注意此时expression是有括号的,因为第一步已经将没有括号的做出判断。
4.如果前面的条件都不吻合,则var 的类型与expression 的类型相同。
另结合使用typedef和decltype:
template <class T1,class T2>
void ft(T1&x, T2 &y)
{
typedef decltype(x+y) xytype;
xytype xpy=x+y;
xytype arr[10];
xytype & rxy =arr[2];
}
C++11的后置返回类型:
Template<class T1,class T2>
Auto gt(T1 X,T2 Y)->decltype(x+y)
{
return x+y;
}
#include<iostream>
#include<cctype>
#include<cstring>
using namespace std;
//++++++++++++++++++++++++++1++++++++++++++++++++++++++++
/*const int size=200;
void print_str(const char *,int);
int main()
{
char s[size];
cout<<"enter your str"<<endl;
cin.getline(s,size);
//cin.get();
int num;
cout<<"enter your num"<<endl;
cin>>num;
cin.get();
print_str(s,num);
return 0;
}
void print_str(const char *str,int n=0)
{
cout<<" cout str "<<*str<<" n "<<n<<"times"<<endl;
if(n>1)
{
n--;
print_str(str,n);
}
}*/
//++++++++++++++++++++++++2+++++++++++++++++++++++++++++++
/*const int size=30;
struct candybar
{
char name[size];
double weights;
int hots;
};
void set_st(candybar &,const char *,double,int);
void show_st(const candybar &);
int main()
{
candybar *pt=new candybar;
char *s;
double w;
int h;
cout<<"enter your string"<<endl;
cin.getline(s,size);
cout<<"enter your weights"<<endl;
cin>>w;
cin.get();
cout<<"enter your hots"<<endl;
cin>>h;
cin.get();
set_st(*pt,s,w,h);
show_st(*pt);
return 0;
}
void set_st(candybar &candy,const char *str="Millennium Munch",double weight=2.85,int hot=350)
{
cout<<"enter your name" <<endl;
//cin.getline(*str,size);
cout<<"enter your weights"<<endl;
//cin>>weight;
cout<<"enter your hot"<<endl;
//cin>>hot;
strcpy(candy.name, str);
candy.weights=weight;
candy.hots=hot;
}
void show_st(const candybar &candy)
{
cout<<candy.name<<endl;
cout<<candy.weights<<endl;
cout<<candy.hots<<endl;
}*/
//++++++++++++++++++++++++++3++++++++++++++++++++++++++++++++++++++++
/*void upper(string &);
int main()
{
string a;
cout<<"enter a string(q to quit)"<<endl;
getline(cin,a);
while(a!="q"&&a!="Q")
{
upper(a);
cout<<a<<endl;
cout<<"next string(q to quit)"<<endl;
getline(cin,a);
}
}
void upper(string &str)
{
for(int i=0;i<str.size();i++)
{
if(islower(str[i]))
str[i]=toupper(str[i]);
}
}*/
//++++++++++++++++++++++4++++++++++++++++++++++++++++++++++++++++++
/*struct stringy {
char *str;
int ct;
};
void set(stringy &in_stringy, char * in_string)
{
char *pt;
int string_length = strlen(in_string);
pt=new char(string_length+1);
//in_stringy.str = new char(string_length + 1);
//strcpy(in_stringy.str, in_string);
strcpy(pt,in_string);
in_stringy.str=pt;
in_stringy.ct = string_length;
}
void show(const stringy &in_stringy, int print_times = 1)
{
for (int i = 0; i < print_times; i++)
{
cout << "member string of struct stringy: " << in_stringy.str << endl;
}
}
void show(const char * str, int print_times = 1)
{
for (int i = 0; i < print_times; i++)
{
cout << "Print char string: " << str << endl;
}
}
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing);
show(beany);
show(beany, 2);
testing[0] = 'D';
testing[1] = 'u';
show(testing);
show(testing, 3);
show("Done!");
return 0;
}*/
//+++++++++++++++++++++++++++++++++++5++++++++++++++++++++++++++++++++
/*template<class T>
T max5(const T arr[5]);
int main()
{
int a[5]={1,2,3,4,5};
double b[5]={1.11,2.22,3.33,4.44,5.66};
int x=max5(a);
double y=max5(b);
cout<<x<<" "<<y<<endl;
return 0;
}
template<class T>
T max5(const T arr[5])
{
T temp=0;
for(int i=0;i<5;i++)
{
if(temp<arr[i])
temp=arr[i];
}
return temp;
}*/
//+++++++++++++++++++++++++++++++++++++6++++++++++++++++++++++++++++++++++
/*template<class T>
T maxn(T arr[],int n);
template<>
char *maxn(char *arr[],int n);
int main()
{
int a[6]={1,2,3,4,5,6};
double b[4]={1.2,2.3,4.5,6.7};
char *str[5]={"a","bb","ccc","dddd","eeeee"};
int x=maxn(a,6);
double y=maxn(b,4);
char *z=maxn(str,5);
cout<<x<<" "<<y<<" "<<z<<endl;
return 0;
}
template<class T>
T maxn(T arr[],int n)
{
T temp;
for(int i=0;i<n;i++)
{
if(temp<arr[i])
temp=arr[i];
}
return temp;
}
template<>
char *maxn(char *arr[],int n)
{
char *a=arr[0];
for(int i=1;i<n;i++)
{
if(strlen(a)<strlen(arr[i]))
a=arr[i];
}
return a;
}*/
//+++++++++++++++++++++++++++++++++++++++7++++++++++++++++++++++++++++++++++++
/*template <typename T>
T SumArray(T arr[], int n);
template <typename T>
T SumArray(T * arr[], int n);
struct debts {
char name[50];
double amount;
};
int p8_7(void)
{
int thing[6] = { 13, 31, 103, 301, 310, 130 };
int int_sum = 0;
struct debts mr_E[3] =
{
{"Ima Wolfe", 2400.0},
{"Ura Foxe", 1300.0},
{"Iby Stout", 1800.0}
};
double *pd[3];
double double_sum = 0.0;
for (size_t i = 0; i < 3; i++)
{
pd[i] = &mr_E[i].amount;
}
int_sum = SumArray(thing, 6);
double_sum = SumArray(pd, 3);
cout << "Sum of int array: " << int_sum << endl;
cout << "Sum of double* array: " << double_sum << endl;
return 0;
}
template <typename T>
T SumArray(T arr[], int n)
{
// 下面的sum初始化,在便宜的时候会有warning提示,有个简单的方法可以解决,那就是将sum初始化为arr的第一个元素,然后for循环从i=1开始
T sum = 0.0;
for (int i = 0; i < n; i++)
{
sum += arr[i];
}
return sum;
}
template <typename T>
T SumArray(T * arr[], int n)
{
T sum = 0.0;
for (int i = 0; i < n; i++)
{
sum += *(arr[i]);
}
return sum;
}
// main
int main(int argc, char **argv)
{
p8_7();
while (cin.get());
}
*/
//++++++++++++++++++++++++++++++++++7(wrong)++++++++++++++++++++++++++++++++++
/*
struct debts
{
char name[50];
double amount;
};
template<class T>
T sumarray(const T arr[],int );
int main()
{
int things[6]={13,31,103,301,310,130};
debts mr[3]=
{
{"ina",2400.0},
{"hehe",1300.0},
{"iby su",1800}
};
int a=sumarray(things,6);
cout<<"numbers in things are "<<a<<endl;
double b=sumarray(mr,3);
cout<<"numbers in debts are "<<b<<endl;
return 0;
}
template<class T>
T sumarray(const T arr[],int n)
{ T sum=0;
for(int i=0;i<n;i++)
{
sum+=arr[i];
}
return sum;
}
template<>
double sumarray(debts (&deb)[],int num)
{
double sum;
for(int i=0;i<num;i++)
{
sum+=deb[i].amount;
}
return sum;
}*/