《Essential C++ 》读书笔记之第一二章

1 篇文章 0 订阅


面向过程

函数声明

函数必须先被声明,之后才能被引用/调用,声明不必提供函数体,但必须指明返回类型、函数名、参数列表。

int fibon_elem(int pos);
//
bool fibon_elem(int pos, int &elem);
//
bool fibon_elem(int, int &);
//目的只是让编译器知道这个函数的存在

头文件

cstdlib

终止整个程序的时候,可以使用exit()这个函数。而在cstdlib这个头文件当中,就包含了这个函数。

limits

想知道某个类型中的最大最小值时,可以查询limits class。

#include <limits>
int max_int = numeric_limits<int>::max();
double min_db1 = numeric_limits<double>::min();

调用函数

Vector

Vector是一种数组,既然是一种数组,那么肯定有普通数组的一系列特性,比如可以通过下标对数组当中的元素进行引用。Vector也是一种可以存放任意动态类型的数组。综上,称之为容器。

基本操作
  • 使用时候要加入头文件#include
  • 声明vector:vector vec;
  • vector数组的初始化
vector<int> vec(1,2,3);
//
vector<int> vec(a);
//a这个向量给vector初始化
int ia[8] = {1,2,3,4,5,6,7,8};
vector<int> vec(ia, ia+8);
//以上这两行操作是把ia当中的元素来给vector进行初始化
vector<int> vec(&m[0], &m[10])//将m[0]~m[10]范围内的元素给vector进行初始化
//vector的基本操作
vec.push_back(i)//在尾部插入i
vec.insert(vec.begin(),i)//在第一个元素之前插入i
vec.assign(5,1)//插入5个1
vec.pop_back()//相当于pop出栈
vec.erase(vec.begin());
//删除第一个元素的数值
vec.clear();
//
vec.empty();
//
//遍历vec
vector<int> vec;
for(int i=0;i<vec.size();++i){
	cout << vec[i];
}
//利用迭代器进行访问
vector<int>::iterator iter;
for(iter=vec.begin();iter!=vec.end();iter++){
   cout << *iter;
}
//建立二维数组
cin >> n >> m
vector<vector<int>>vec(n);
for(int i=0;i<n;++i){
	vec[i].resize(m);
}

传值(Pass by value)

例如有一个swap函数

void swap(int val1, int val2)
{
	int temp = val1;
	val1 = val2;
	val2 = temp;
}

在主函数当中,swap被调用之后,其实从vector当中传给swap()函数的对象被复制了一份(vector中的对象传入函数当中是会被默认复制一份的,成为参数的局部性定义),原对象与副本之间是没有任何关联的。

传址(Pass by reference)

令swap()的参数和传入的实际对象产生关联,这就是所谓的传址,把真正的地址给传进去,就能把真实值给改变。

void swap(int &val1, int &val2)
{
	int temp = val1;
	val1 = val2;
	val2 = temp;
}

所以,要真正改变vector当中对象的数值时,要使用传址而不是传值。

作用域

对象在程序内的存活区域成为对象的scope(作用域)。
对象如果在函数以外声明,具有所谓的file scope,相当于全局变量。
local scope之内的,相当于局部变量,需指定参数,否则不会被初始化。

动态内存管理

local scope与file scope,都是系统自动分配空间的。
分配:new
释放:delete

int *pi;
pi = new int;
//
delete pi;

局部对象的地址返回会出现错误,但是有一个例外(指的是static)。
局部静态对象所处的内存空间,即使在不同的函数调用过程当中,依然持续存在。

cerr

全局对象 std::cerr 和 std::wcerr 控制到实现定义类型(分别导出自 std::streambuf 和 std::wstreambuf )的流缓冲,与标准 C 错误输出流 stderr 关联。

inline function

将之前分散开来的各个独立的函数,整合进一个函数内,但任然保持n个独立的运算单元,这就是inline function,只需在头文件处加上inline即可。

重载函数

C++特性,参数列表不想同的两个或者多个函数,可以拥有相同的函数名称,这就是函数的重载。需要注意的是不能通过返回的类型来区分两个不同函数的语境。

int sum(int x, int y)
{
    cout << "sum(int, int) is called" << endl;
    return x + y;
}
float sum(float x, float y)
{
    cout << "sum(float, float) is called" << endl;
    return x + y;
}
double sum(double x, double y)
{
    cout << "sum(double, double) is called" << endl;
    return x + y;
}

函数模板

template <typename elemType>
void display_message(const string &msg, const vector<elemType> &vec)
{
.......
}

此处的关键字typename以及elemtype只是占位符。当指定了vector的数据类型时,elemType才会绑定相应的类型。

这个模板既可以是函数模板也可以是参数模板。template本身也可以做类型,相当于套娃。
函数模板的 其中的elemType要与之后的elemType开头相同。

template<typename T>
T sum(T x, T y)
{
cout << "The input type is " << typeid(T).name() << endl;
return x + y;
}

编译器看到这个函数时,编译器不知道怎么做,因为不知道类型。要调用函数模板的话,就得进行实例化。

template double sum<double>(double, double);
//一种更简化的类型就是下面
template int sum(int, int);
template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x +
     y;
}
// Explicitly instantiate
template double sum<double>(double, double);

int main()
{
    auto val = sum(4.1, 5.2);
    //auto就是返回值是什么类型,这个val就是什么类型
    cout << val << endl;
    return 0;
}

在实例化当中进行类型的赋值就行,实例化之后直接在main函数当中调用这个函数就行。
注意,模板的调用分显式的实例化还有隐式的实例化,就是不一定非要把实例化写出来。

template<typename T>
T sum(T x, T y)
{
    cout << "The input type is " << typeid(T).name() << endl;
    return x + y;
}

int main()
{
    // Implicitly instantiates product<int>(int, int)
    cout << "sum = " << sum<int>(2.2f, 3.0f) << endl;
    // Implicitly instantiates product<float>(float, float)
    cout << "sum = " << sum(2.2f, 3.0f) << endl;

    return 0;
}

结构体也可以是一个类型,不过其实例化是一个特例化,要加上一个尖括号<>。

普通的实例化如下

template
double sum<double>(double, double);
//特例化如下
template<>
Point sum<Point>(Point pt1, Point pt2);
//Point代表结构体类型

函数指针

必须指明所指函数的返回类型以及参数列表,以及赋予一个名称。

const vector<int>* (*seq_ptr)(int);

在这,参数列表内容为int,返回类型为const vector*。
若要显示循环,在每次迭代过程中将seq_ptr设置为各个不同的数列函数,可以利用数组索引的技巧。

const vector<int> * (*seq_array[])(int) = {
fibon_seq, lucas_seq.........
}

设定头文件

尖括号就是从编译器指定的include路径去找头文件,双引号就是从不光从编译器指定的路径找,而且还从当前这个cpp文件的当前目录去找。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值