笔记2

感觉这玩意还挺好用的。

C++

11.编程模块

getline(cin,list[i]); // 查查相关函数

如果用count< string sa[];

函数指针

将函数的地址传递给另一个函数:

  1. 获取函数的地址。要将函数作为参数进行传递,必须传递函数名。
  2. 声明一个函数指针。声明应指定函数的返回类型以及函数的特征标(参数
    列表)。原型:double pam(int);声明为double (*pf)(int);然后地址赋值
    pf=pam。
  3. 使用函数指针来调用函数。

用typedef减少输入量

typedef const double *(*p_fun)(const double *, int); // p_fun是新类型名
p_fun p1=fun1;
12.

使用内联函数,必须采取下述措施之一:

  1. 在函数声明前加上关键字inline
  2. 在函数定义前加上关键字inline
inline double square(double x) { return x*x }  // 与C宏不太相同
13.

(左值)引用变量用作参数,函数将使用原始数据,而不是副本。
引用变量必须在声明引用时将其初始化,不能先声明后赋值。一旦与某个变量关键起来,就将一直效忠于它。引用不能为空,指针可以为空。

int rats;
int & rodents = rats; // int &指的是指向int的引用
// rats和rodents可以互换,它们指向相同的值和内存单元。
void swapr(int &a,int &b); // 声明函数,参数为引用变量
swapr(wallet1,wallet2); // 调用函数
// 结构的情况
struct free_throws
{
  std::string name;
  int made;
  int attempts;
  float percent;
}
vois set_pc(free_throws & ft); // 函数原型,将指向结构体的引用作为参数
void display(const free_throws & ft); // 不希望函数修改传入的结构

如果实参与引用参数不匹配,仅当参数为const引用时,c++将生成临时变量。
(什么时候将创建临时变量?如果引用参数是const,1.实参的类型正确,但不是左值[左值参数是可被引用的数据对象,const变量属于不可修改的左值]。2.实参的类型不正确,但可以转换为正确的类型。)

尽可能使用const:

  1. 使用const可以避免无意中修改数据的编程错误;
  2. 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
  3. 使用const引用使函数能够正确生成并使用临时变量。

使用值传递、引用、指针的一些指导原则(还是要根据实际情况来选):

  • 对于使用传递的值而不作修改的函数:
    1.如果数据对象很小,如内置数据类型或小型结构,则按值传递
    2.如果数据对象是数据,只能用指针,并将指针声明指向const的指针
    3.如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省赋值结构所需的时间和空间。
    4.如果数据对象是类对象,则使用const引用
  • 对于修改调用函数中数据的函数:
    1.如果数据对象是内置数据类型,则使用指针
    2.如果数据对象是数组,则只能使用指针
    3.如果数据对象是结构,则使用引用或指针
    4.如果数据对象是类对象,则使用引用
14.

继承:能够将特性从一个类传递给另一个类的语言特性。
例如:ostream是基类,而ofstream是派生类。
派生类继承了基类的方法,派生类可以使用基类的特性。** 基类引用可以指向派生类对象,而无需进行强制类型转换。可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可以将派生类对象作为参数。 **例如,参数类型为ostream &的函数可以接受ostream对象(如cout)或您声明的ofstream对象作为参数。

void file_it (ostream & os,double fo,const double fe[],int n); // 内有os<<"内容"等语句
ofstream fout;
file_it(fout,objective,eps,LIMIT); // 将数据写入到fout指向的文件中
file_it(cout,objective,eps,LIMIT); // 将同样的信息以同样的格式显示到屏幕上
// 参数os(其类型为ostream &)可以指向ostream对象(如cout),也可以指向ofstream对象(如fout)
15.
  • 方法setf()能够设置各种格式化状态
    例如,setf(ios_base::fixed)将对象置于使用定点表示法的模式;setf(ios_base::showpoint)将对象置于显示小数点的模式,即使小数部分为0;
    setf(ios_base::boolalpha)将对象置于显示true或false的模式,而不是0或1。
    假如对象处于定点模式下,方法precision()指定显示多少位小数。
    所有这些设置都将一直保持不变,直到再次调用相应的方法重新设置它们。
  • 方法width()设置下一次输出操作使用的字段宽度,这种设置只在显示下一个值时有效,然后将恢复到默认设置。默认字段宽度为零(刚好能容纳要显示的内容)。
ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed); // 获得当前的格式化状态
……
os.setf(initial); // 在设置了其他状态后回到原始的格式化模式
16.

默认参数指的是当函数调用中省略了实参时自动使用的一个值。

char * left (const char * str, int n=1); // 1为n的默认值,在声明原型的时候赋值

对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。

int harpo(int n, int m=4, int j=5); // 合法
int chico (int n, int m=6, int j); // 不合法
17.函数重载

术语“多态”与“函数重载”是一回事。
函数重载的关键是函数的参数列表——也称为函数特征标。c++允许定义名称相同的函数,条件是它们的特征标不同,而不是函数类型使得可以对函数进行重载。(返回值类型可以不同,但特征标也必须不同)

  • 如果在使用被重载的函数时,实参与任何原型不匹配,c++将尝试使用标准类型转换强制进行匹配,但如果有多个可强制类型转换的原型,c++将拒绝这种函数调用,并将其视为错误。
  • 如果一些看起来彼此不同的特征标是不能共存的。
double cube(double x);
double cube(double &x);
cout<< cube(x); // 编译器无法确定究竟应使用哪个原型

为避免这种混乱,编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。

  • 如果匹配函数时,参数有const和非const变量,不会区分的。
    将非const值赋给const变量是合法的,反之则是不合法的。

仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。

18.函数模板/通用编程/参数化类型(通用的函数描述,用泛型来定义函数)

关键字template和typename是必需的,除非可以使用关键字class代替typename。必须使用尖括号。

template  // AnyType(类型名)可用int,double等代替
void swap (AnyType &a , AnyType &b> // 交换a和b的值
{
  AnyType temp;
  temp=a;
  a=b;
  b=temp;
}

如果需要多个将同一种算法用于不同类型的函数,使用模板。一般应使用关键字typename而不使用class。

19.重载的模板

被重载的模板的函数特征标必须不同。(并非所有的模板参数都必须是模板参数类型)

20.显式具体化
  • 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
  • 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。
// 下面的声明是一样的
template<>void swap(job &,job &);
template<>void swap(job &,job &);
  • 具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

** 实例化和具体化 :**
编译器使用模板为特定类型生成函数定义时,得到的是模板实例。

  • 隐式实例化和显式实例化:隐式是由于程序调用了某函数时提供了(类型)参数;显式实例化是直接命令编译器创建特定的实例,如swap(),声明所需的种类——用<>符合指示类型,并在声明前加上关键字template:
template <> void swap(int ,int );
  • 显式具体化:
template <> void swap (int &,int&);
template <> void swap(int &,int &);

“不要使用swap()模板来生成函数定义,而应使用专门为int类型显式地定义的函数定义。”这些原型必须有自己的函数定义。显式具体化声明在关键字template后包含<>,而显式实例化没有。

  • 试图在同一个文件(或转换单元)中使用 类型的显式实例和显式具体化将出错。

隐式实例化、显式实例化和显式具体化统称为具体化。它们表示的都是使用具体类型的函数定义,而不是通用描述。
** 重载解析:**
过程:1.创建候选函数列表。
2.使用候选函数列表创建可行函数列表。
3.确定是否有最佳的可行函数。
查看为使函数调用参数与可行的候选函数的参数匹配所需要进行的转换,最佳到最差的顺序:
1.完全匹配,但常规函数优于模板。
2.提升转换(例如,char和shorts自动转换为int,float自动转换为double)
3.标准转换(例如,int转换为char,long转换为double,char转换为double)
4.用户定义的转换,如类声明中定义的转换。
通常有两个函数完全匹配是一种错误,但有两个例外,完全匹配和最佳匹配:
Type(argument-llist)意味着用作实参的函数与用作形参的函数指针只要返回类型和参数列表相同,就匹配。

从实参---------------------------------到形参
Type------------------------------------Type &
Type &---------------------------------* Type
Type[]----------------------------------* Type
Type(argument-list)----------------Type (*)(argument-list) // 名为Type的函数
Type-----------------------------------const Type
Type-----------------------------------volatile Type
Type *---------------------------------const Type
Type *---------------------------------volatile Type *

如果有多个匹配的原型,且没有最佳的可行函数,编译器将无法完成重载解析,可能会有诸如二义性的错误消息。但有时候 及时有两个函数完全匹配,仍可完成重载解析:

  • 指向非const数据的指针和引用优先与非const指针和引用参数匹配,然而const和非const之间的区别只适用于指针和引用指向的数据。
  • 如果其中一个是非模板函数,另一个不是,那么非模板函数将优先于模板函数。
  • 如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先。
    “最具体”指编译器推断使用哪种类型时执行的转换最少。(部分排序规则)

** 关键字decltype: **

// decltype(expression) var;

template
void ft(T1 x, T2 y)
{
  ……
  decltype(x+y) xpy=x+y;
……
}

long indeed(int);
decltype(indeed(3)) m; // m是long型
// 不会实际调用函数。

// 如果expression是一个左值,则var为指向其类型的引用。
double xx=4.4;
decltype ((xx)) r2 =xx; // r2是double &型,要用括号括起来
decltype (xx) w= xx; // w是double型

template 
auto gt(T1 x, T2 y)->decltype(x+y)
{
  ……
  return x+y;
}

你可能感兴趣的:(笔记2)