2013年12月3日星期二

Learning C++ Primer Plus chapter 8 - 9

这几周主要在学习8-9章,涉及到得新的知识点越来越多,导致学习的进度并不是很快,后面的学习速度需要提高一下

第八章的主要内容是讲cpp中得函数的使用,包含内联函数,引用变量,函数重载,函数模板等主题,大部分内容是以前有过了解,但是从未深入的,渐渐的感觉到了cpp的强大,对C语言的进化

第九章的主要内容是关于内存模型和名称空间的,这类涉及到得细节相对多一点,知识点本身病不是很多

下面主要列一下在这两章中学习到得一些知识点:


一、引用
在说引用之前,先说一下左值和右值,先看下wikipedia上得解释
  • * L-valueAn expression (computer science) that designates an object▫
  • * see alsohttp://www.iso-9899.info/n1570.html#6.3.2.1
  • * r-value, in computer science, a value that does not have an address in a computer language
其实从上面来看,左值和右值的本质区别应该是是否可以被改变,简单的区别办法就是在等号左边的即是左值,它本质是一个对象,在内存中是一个实际的地址,可以往这个地址里存储符合的值,而右值可以是一个表达式,也可以是一个值,右值中的数据只能被读取,不能写入,也就是不能被改变

在c++11中,在原有的引用的基础上,新增了右值引用,原来的引用办法,现在被称之为左值引用,下面看下简单的例子

左值引用:
  double a = 1.2;
 
 double & b = a;
  cout << b << endl;
右值引用:
 
 double && c = 1 + 3.4;
  cout << c << endl;
在正常的情况下,直接使用右值做引用是不可以的,但是现在在C++11中,是可以的,目前具体的右值引用的使用场景还没有见到,在到后面使用时,再做详细的说明。



二、函数重载(多态)
函数重载的要点在于函数的参数列表,也被称之为函数特征标,函数的返回值类型,可以相同也可以不同,但是特征标,必须不用
还有一点是,编译器在检查函数特征标的时候,将会吧类型引用和类型本身,视为相同的特征标
double cube(double x)
double cube(double & x)
所以如果同时定义了这两个函数,那么就是不合法的,编译器将不知道使用哪个函数来做处理



三、函数模板(泛型)

函数模板,就是通过泛型来定义函数,当传递具体的类型给模板,可以让编译器生成具体的类型的函数,模板因为允许以泛型来编写程序,因此也被称之为通用编程,通过模板,我们可以将以前大多数的工作量通过模板来简化。

如果以前需要重载int double float三种类型的函数,那么需要手工写三次,如果使用模板,那么只需要写一次即可,编译器会自动为你完成剩余的工作。

定义方式:
template <typename T>void show_value(typename &t);

在c++98之前,没有关键字typename,使用class来创建模板
template <class T>
void show_value(class &t);

上面的二者是等价的



C++具体化方法
1.对于给定的函数名,可以有非模板函数,模板函数和显式具体化的模板函数以及他们的重载版本
2.显式具体化的原型和定义是以template <> 打头,并通过名称来指出类型
3.非模板函数优先于具体化,优先于常规模板

三种原型:
//非模板函数:
void swap(job &,job &);

//显式具体化:用户自定义 TODO
template <> void swap<job>(job &, job &);
template <> void swap<int>(int &, int &);
template <> void swap(int &, int &);

//常规模板:
template <typename T>
void swap(T &, T &);

实例化:我们在上面定义的函数模板,仅仅是对于生成函数的一个描述信息,而并非真正的函数本身,当程序在执行的过程中,编译器根据传入的参数,生成具体的真实的函数的过程,称之为实例化。最初的c++只能通过隐式实例化来使用函数模板,现在c++可以支持显式实例化,可以直接让编译器生成自己所需要的函数定义。

显式实例化:通过用户传入的参数,编译器根据模板来生成符合要求的函数实例
语法:template void swap<int>(int, int);

隐式实例化:用户自己指定参数来让编译器通过模板生成符合用户需要的函数实例


隐式实例化,显式实例化,显式具体化,统称为具体化,相同之处在于,表示的都是使用具体类型的函数定义,而不是通用描述

四、存储持续性
在前面说过,c++的有几种存储方案来存储不同的数据,分别是
自动存储持续性:栈
静态存储持续性:静态存储区
动态存储持续性:堆

在c++11中,新增县城存储持续性,主要应用于多线程编程中,这让程序能够将计算放在可并行处理的不用线程中,使用关键字thread_local声明,其生命周期与所属的线程一样长


五、寄存器变量register
在c语言以及早期的c++中,register关键字声明的变量,表示寄存器变量,即建议编译器将其存储在cpu的寄存器中,因硬件和编译器变得越来越复杂,所以在c++11中,关键字register的这种提示作用失效了,现在的register只是显式的支出变量是自动的


六、定位new运算符
在一般情况下,new运算符,从堆中申请置顶大小的内存块,但在实际应用中,new还有一种被称之为定位new运算符的变体,它可以在指定的位置申请内存块,比如静态存储区,栈,堆等,我们可以使用这种特性来设置内存管理规程,处理需要通过特定地址才能访问的硬件,以及在特定的位置创建对象

使用方法:
#include <iostream>
#include <new> // for placement new
const int BUF = 512;const int N = 5;char buffer[BUF];      // chunk of memory
int main()
{
   
 using namespace std;

   
 double *  pd1 = new (buffer) double[N];  // use buffer array
    cout << &buffer << endl;
    cout << pd1 << endl;
   
 return 0;
}
执行输出结果:
0x10f1e2070

0x10f1e2070

可以看到,pd1的地址,与buffer的起始地址是一样的,所以pd1实在buffer上面申请的一块空间。


没有评论:

发表评论