Essential c++初学 第二章 basic c++ programming

本文介绍了C++的基础编程概念,包括函数的声明与定义、引用传参、冒泡排序、局部静态变量、重载函数、函数模板的使用,以及函数指针和头文件的管理。讲解了如何利用函数模板实现代码复用,以及如何通过函数指针间接调用函数。同时强调了头文件在项目中的作用和包含方式。
摘要由CSDN通过智能技术生成

1. 函数申明及定义
pass by reference

int ival = 1024;//对象,类型为int
int *pi = &ival //pointer ,指向int对象
int &rval = ival //reference引用,代表一个Int对象
#include <iostream>
//前置声明,告诉编辑器有这个函数存在
bool fibon_elem(int, int &);

int main() {
	int pos;
	std::cout << "please enter a position:";
	std::cin >> pos;

	int elem;
	if (fibon_elem(pos, elem))//利用函数返回的true or flase来做if的判断条件
		std::cout << "element #" << pos
		<< "is" << elem << std::endl;
	else
	{
		std::cout << "sorry,could not calculate element" << pos << std::endl;
	}
	system("pause");//抓不住黑框用system("pause"),或者getchar()
}

//&指向elem的内存区域,相当于一个内存区域对应两个变量名字,通过一个渠道改变,真正的值就改变了
bool fibon_elem(int pos, int &elem) {

	if (pos <= 0 || pos > 1024) {
		elem = 0;
		return false;
	}//有if不一定写else,可以保证代码整洁性。

	elem = 1;
	int n_2 = 1, n_1 = 1;
	for (int ix = 3; ix <= pos; ++ix) {
		elem = n_2 + n_1;
		n_2 = n_1;
		n_1 = elem;
	}
	return true;
}

2. 冒泡排序以及&传址(pass by reference)

#include <vector>
#include <iostream>
#include <fstream>
//#include "NumericSeq.h"
//void display(const std::vector<int> &, std::ostream& = std::cout);




/*disply函数的第一个参数位置使用&时为了加速,对象本身不会复制出另外一份,
加上const是为了让阅读程序的人了解我们以传址的目的不是为了在函数中修改vector。
第二个参数位置使用&是为了修改os输出口,摆脱局部变量的作用域限制
和下方的bubble_sort中的ofstream *ofil = 0区别就是这里的os一定要给个地方输出,
而下方的是一个可选参数,当用户给参数时才激活,利用了指针值为0就是空指针的特性*/
void display(const std::vector<int> vec,std::ostream &os = std::cout ) {
	for (int ix = 0; ix < vec.size(); ++ix)
	{
		std::cout << vec[ix] << ' ';
		std::cout << std::endl;
	}

}

//若没有&号,则是pass by value,实际参数传入函数后,仅是被复制了一份
//复制后参数和原来的参数之间没有具体的物理联系,用了&号相当于到原参数的内存地址修改
void swap(int &vall, int &val2) {
	int temp = vall;
	vall = val2;
	val2 = temp;
}

std::ofstream outfile("D:/c++_test/text_out1.txt");
void bubble_sort(std::vector<int> &vec,std::ofstream *ofil = 0) {
	for (int ix = 0; ix < vec.size(); ++ix)
	{
		for (int jx = ix + 1; jx < vec.size(); ++jx)
		{
			if (vec[ix] > vec[jx]) {
				outfile << "about to call swap! ix:" << ix << "jx:" << jx
					<< "\tswappong:" << vec[ix] << "with" << vec[jx] << std::endl;


				swap(vec[ix], vec[jx]);
			}
		}
	}

}


int main() {
	//ia是一个array,先定义一个array然后一一赋值给vector
	int ia[8] = { 8,34,3,13,1,21,5,2 };
	std::vector<int> vec(ia, ia + 8);
	std::cout << "vector before sort:";
	display(vec);
	bubble_sort(vec,&outfile);
	std::cout << "vector after sort :";
	display(vec);
	system("pause");
}

3.局部静态变量


```cpp
#include <vector>
#include <string>
#include <iostream>

//定义一个返回 容器类型指针 的函数
const std::vector<int>* fibon_seq(int size) {
	const int max_size = 1024;
	static std::vector<int>elems; //定义局部变量 elems存放实际数据
	//局部静态变量对象所处的内存空间,即使在不同的函数调用过程中,依然持续存在
	if (size <= 0 || size > max_size) {
		std::cerr << "fibon_seq():oops:invalid size:"
			<< size << "--can't fulfill request.\n"<<std::endl;
		return 0;
	}

	for (int ix = elems.size(); ix < size; ++ix)
	{
		if (ix==0||ix ==1)
		{
			elems.push_back(1);}
		else
		{
			elems.push_back(elems[ix - 1] + elems[ix - 2]);
		}
		
	}
	return &elems;//elems是一个地址
}

void display() {
	int a;
	std::cout << "enter the size number";
	std::cin >> a;
	const std::vector<int> elems = *fibon_seq(a); //*地址 相当于'解包'
	for (auto it = elems.begin(); it != elems.end(); ++it) //elems.end()尾指针 it加的是地址值
	{
		std::cout << "the elems is "
			<< *it << std::endl;//*it 打印出it的数值
	}
	system("pause");
}

int main() {
	std::string go_on;  //Q:为啥char不行 A:因为双引号是str,单引号才是char
	std::cout << "it's ready go on (y/n)\n";
	std::cin >>  go_on;
	for (; go_on == "y";) {
		display();	
		}
	system("pause");
}

4.inline函数。
面对一个inline函数,编译器可以将该函数的调用操作改为以一份函数代码副本替代,这主要是为了获得更好的性能,从结果上来看,等于是帮三个函数写入fibon_elem()内,但依然维持三个独立的运算单元。

 #include <vector>
#include <string>
#include <iostream>

bool is_size_ok(int size) {
	const int max_size = 1024;
	if (size <= 0 || size > max_size) {
		std::cerr << "fibon_seq():oops:invalid size:"
			<< size << "--can't fulfill request.\n" << std::endl;
		return false;}
	return true;
}

const std::vector <int>* fibon_seq(int size) {
	const int max_size = 1024;
	static std::vector<int> elems;
	if (!is_size_ok(size))
		return 0;
	for (int ix = elems.size(); ix < size; ++ix)
	{
		if (ix == 0 || ix == 1)
			elems.push_back(1);
		else
			elems.push_back(elems[ix - 1] + elems[ix - 2]);	
	}
	return &elems;
}

 inline bool fibon_elem(int pos, int &elem)
{
	const std::vector<int>*pseq = fibon_seq(pos);
	//当fibon_seq没有返回值 执行if
	if (!pseq) {
		elem = 0;
		return false;
	}
	elem = (*pseq)[pos - 1];
	return true;

}

5.重载函数(function overloading)
为了使得可以向函数传入不同类型甚至不数量的参数(统称parameter list)
步骤一:申明多个同名重载函数
步骤二:调用

//e.g.
void display_meassage(char ch);
void display_meassage(const string&);
void display_meassage(const string&,int);
void display_meassage(const string&,int,int);

调用时,编译器会将调用者提供的实际参数拿来和每个重载函数参数做比对,找出其中最合适的。
注意,只有传入参数是可以不同的,如果是同名函数的返回参数不同并不能使用重载函数的写法。

ostream&display_message(char ch);
bool display_message(char ch);
//调用时出现歧义,无法确定要调用哪个函数。
display_message('\t')

6.函数模板 template functions
有时,函数的传入参数类型只是有些许不同,因此我们写函数的时候希望推迟决定数据类型,希望在用户调用函数的时候才进行决定,这时候就使用template functions。标识符相当于一个占位符的角色。

//e.g.
template <typename elemType>
void display_message(const string &msg,const vector <elemType &vec>)
{
	cout<<msg;
	for(int ix =0;ix<vec.size();++ix){
		elemType t = vec[ix];
		cout<<t<<'';
}
}

typename关键字,表示elemType在函数中是一个占位符,这个elemType是我自己任意定义的名字。
当使用function template时,只需要先声明一次占位符那个位置的变量的类型再调用即可,如:

//接上一个片段

vector<int>ivec;
string msg;
//...
display_message(msg,ivec)

vector<string>ivec;
string msg;
//...
display_message(msg,ivec)

by the way,fuction template also can be a function overloading重载函数

//fuctioin template with overloaded
template<typename elemType>
void display_message(const string &msg,const vector<elemType>&vec)

template<typename elemType>
void display_message(const string &msg,const list<elemType>&lt)

7.函数指针 pointer to functions

//样例:
const vector<int>*(*seq_ptr)(int);

const vector*指返回类型,返回一个放有Int的容器型指针,(*seq_ptr)是函数指针的定义,现在的函数是个函数指针型函数,(int)表示传入的参数列表。

调用时,与一般函数相同

const vector<int>*pseq = seq_pre(pos);

这样,这种语句会间接调用seq所指向的函数,我们在这里并不知道它指向的是哪个函数,只有通过将函数的地址赋给函数指针,

//将pell_seq()的地址赋给seq_ptr
seq_ptr = pell_seq;

8.头文件 header file
一种打包声明的编程习惯,让后期只需为函数维护一份声明即可。
函数定义只能有一份,声明却可以有多份,除了inline函数外,都不把函数定义放进头文件中。

//e.g.
//Numseq.h 通常头文件的扩展名是 .h
bool  seq_elem(int pos, int &elem);
const vector<int>*fibon_seq(int size);
const vector<int>*lucas_seq(int size);
const vector<int>*pell_seq(int size);
//...

在全局变量内定义的对象,如果可能被多个文件访问,就应该被声明于头文件当中。在声明的时候需要加上extern关键字,以防系统误认为是一个定义

//e.g.
extern const vector<int>*(*seq_array[seq_cnt](int))

调用头文件的声明时,只需要include进去就行

#include "Numseq.h"
void test_it()
{
//...
}

需要说明的是,inlude后接" "是用户定义的头文件,搜索此文件时,会从要包含此文件的文件所在磁盘开始查找,而<>代表标准或者项目专属的头文件,编辑器查找时,会现在某些默认的磁盘目录中寻找。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值