目录
C++初步知识
综述
C++初步知识:函数声明、函数重载、函数模板、有默认参数的函数、内联函数(内置函数)、变量的引用、const定义常变量、字符串变量、输入和输出、作用域运算符、动态分配内存/释放内存。
带举例,供学习、参考和查阅。
函数声明
函数声明:调用函数前需做函数原型声明(C是建议性,C++是强制性)。
函数重载
重载:一个标识符多个含义或用途。
函数重载:三个函数名取相同,程序运行时,会根据参数类型、个数的不同,适时调用对应参数类型、个数的函数。
缺点:同名函数很多个时,要一个个编写,编码量大。
适用:实现相类似又不同的函数功能时,例如求多个数值的最大值(3个整型求最大值、2个实型求最大值、3个长整型求最大值,即便三个函数名相同,也会根据参数类型的不同来适时调用对应函数)。
函数模板
函数模板:建立一个通用函数,函数类型和形参类型用虚拟类型指定,函数使用时,可以直接带入参数类型,比函数重载更方便。
建立函数模板的关键字:template。
例:
#include <iostream>
using namespace std;
template <typename T>
T max(T a,T b,T c)//没有实际类型,只有虚拟类型T
{
if(b>a) a=b;
if(c>a) a=c;
return a;
}
……
虚拟类型可以有多个,如:template <typename T1,typename T2>。
typename也可以用class替代,如:template <class T1,class T2>。
建立函数模版时,只需要将函数类型、参数类型换成T即可。
适用:函数体相同、参数个数相同而类型不同。若不满足情况只能使用函数重载。
有默认参数的函数
有默认参数的函数:给参数默认值;当不提供实参时,形参就用默认参数作为实参。
例:
函数声明:
void area(float x1,int x2=1,char x3='a');
函数调用:
area(1.0,2,b);//形参全部由实参得到
area(1.0,2);//最后一参取自默认值
area(1.0);//最后两参取自默认值
area(1.0,b);//不合法,中间x2的的默认参数1要写上
area();//不合法,第一个形参无实参也无默认值
默认参数函数与重载函数互斥:一个是有默认参数的函数int max(int a,int b,int c=100)中,实参max(5,23)合法,但此时若是加上一个常规函数int max(int m,int n),实参max(5,23)就不合法了。所以说一个函数不能既重载,又有默认参数,只能选择其中之一。
一定要在调用函数之前给出默认值。
适用:调用时不好确定参数、经常使用某参数;默认参数在右侧;默认参数与重载函数互斥。
内联函数(内置函数)
内联函数:解决程序中函数调用效率问题,函数调用有时间和空间代价,部分代码短小但使用频率高,开销巨大,所以将函数体嵌入函数调用处,提高效率。
成为内联函数:声明一个函数时,加限定词inline,编译时将调用此函数处用函数原代码替换,即以空间代价换时间。
例:
#include <iostream>
using namespace
inline int power(int x)
{
return x*x;
}//定义内联函数
int main()
{
cout<<power(2)<<endl;//调用内联函数
return 0;
}
适用:代码量少,调用频繁的函数。
变量的引用
引用:变量的引用就是变量的别名。
&:“引用声明符”,不代表取地址。
引用不是独立的变量:编译系统不分配存储单元,建立引用只有声明,没有定义,只是声明和某一个变量的关系。
引用不是独立的数据类型,必须与某一种类型的数据相联系。
使用引用的目的:可以节省空间。
例1:
int a,b;
int &c=a;//读作c是a的引用
int &c=b;//不合法,c已经是a的引用,不能作为b的引用
int &x;//不合法,没有指定x代表哪个变量
例2:
#include <iostream>
using namespace std;
int main()
{
int a=10;
int &b=a;//b=10
a=a*a;//a=100
cout<<"b="<<b<<endl;//b=10
return 0;
}
变量名为形参,形参和实参不是同一个存储单元。
当函数调用时,实参赋值给形参,函数运行时,形参变化但并不回传给实参,如下例:
#include <iostream>
using namespace std;
void swap(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
int main()
{
int i=3,j=5;
swap(i,j);
cout<<i<<","<<j<<endl;//运行结果,i,j仍然是3,5
return 0;
}
所以实参并没有变化。
该如何解决实参不随形参变化而变化这个问题呢?
解决办法1:利用指针,传给形参的是变量的地址,即形参指针变量指向实参变量单元,形参变化,即该指针指向的单元发生变化,如下例:
#include <iostream>
using namespace std;
void swap(int *p1,int *p2)
{
int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}
int main()
{
int i=3,j=5;
swap(&i,&j);//相当于p1=&i和p2=&j,p1和p2交换
//传递的是变量的地址,把i的地址给指针p1(p1指向i),把j的地址给指针p2(p2指向j)
cout<<i<<","<<j<<endl;//运行结果,i,j是5,3
return 0;
}
解决办法2:利用引用,传递变量的别名,将变量的引用作为形参,如下例:
#include <iostream>
using namespace std;
void swap(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
int main()
{
int i=3,j=5;
swap(i,j);//相当于int &a=i和int &b=j,a和b交换
//a是i的引用,b是j的引用
cout<<i<<","<<j<<endl;//运行结果,i,j是5,3
return 0;
}
如何理解引用:引用是一个隐性指针,引用值是引自所指向的实体。
对引用的说明:不能建立void类型的引用,因为任何时间存在的变量都是非void类型;不能对数组名进行引用因为数组名首地址不占用存储空间;可以将引用的地址赋给指针,此时指针指向原变量:
int a=3;
int &b=a;//此时&作用是引用
int *p=&b;//此时&作用是取地址
//指针p指向变量a的引用b,相当于指向a
可以建立指针变量的引用;可以用const对引用加以限定,不允许改变该引用变量的值,但其代表的变量的值可变;可以用常量或表达式对引用初始化,但必须用const限定:
const int &a=3;//合法
const定义常变量
在C中,用#define定义常量,只在预编译时进行字符置换,将标识符置换成表达式或数字,定义的常量不是变量,没有类型,不占用存储单元地址,容易出错,如下例:
int a=1;int b=2;
#define PI 3.14159
#define R a+b
cout<<PI*R*R;//预想输出:3.14159*(a+b)*(a+b)
//实际输出:3.14159*a+b*a+b,所以出错
C++的解决办法:用const定义常变量,有数据类型,占用存储单元地址,可用指针指向;在程序运行中,此常变量值固定,不能改变,如下例:
const float PI=3.14159
用const定义常变量取代#define:定义的常变量占内存;其值不可改变。
字符串变量
头文件string与string.h:
<string>是c++头文件,包含string类,如声明string s1
<string.h>头文件无类,不能声明string s1,但其中包含C常用字符串处理函数,如strcmp
<string.h>在C++中写成<cstring>
字符串定义、赋值、输字符串变量入输出,如下例:
string s1;//定义字符串变量s1
string s2="China";//定义字符串变量s2,初始化
s1="Hello";
s2=s1;
s3=s1+s2;//字符串连接
string c1;
cin>>c1;
cout<<c1;
字符串运算:使用==,!=,>=,<=对字符串进行比较。
字符串数组,如下例:
string name [3]={"张三","李四","王五"}
从键盘输入3个字符串,并按字母由小到大顺序输出,如下例:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string string1,string2,string3,temp;
cout<<"please input three strings:";
cin>>string1>>string2>>string3;
if(string2>string3)
{temp=string2;string2=string3;string3=temp;}
//限定串2≤串3
if(string1<=string2)
{cout<<string1<<" "<<string2<<" "<<string3<<endl;}
//如果串1≤串2,输出串1 串2 串3
else if(string1<=string3)
{cout<<string2<<" "<<string1<<" "<<string3<<endl;}
//如果串1≤串3,输出串2 串1 串3
else cout<<string2<<" "<<string3<<" "<<string1<<endl;
//如果串1>串2,且串1>串3,输出串2 串3 串1
return 0;
}
输入和输出
C的输入输出:scanf和printf,必须指定输入输出格式(如%d)。
C++的输入输出:cin和cout,不用指定输入输出格式,需要头文件iostream。
标准输入流:cin>>
标准输出流:cout<<
作用域运算符
作用域运算符:每个变量都有自己的有效范围,只能在变量作用域内使用变量,不能直接使用其他作用域中的变量,如果要使用其他作用域中的同名变量,必须使用作用域运算符,即"::",如下例:
#include <iostream>
using namespace std;
float a=1.5;//全局变量a
int main()
{
int a=5;
cout<<a<<endl;//局部变量a,输出5
cout<<::a<<endl;//全局变量a,输出1.5
return 0;
}
动态分配内存/释放内存
C:用函数malloc(size)/free实现内存管理。
malloc(size):不知道数据类型,无法返回类型指针,用void*返回,做强制类型转换
C++:用运算符new/delete实现内存管理(不是函数,执行效率高)。
分配内存空间:new 类型 [初值]
释放内存空间:delete[ ] 指针变量
如下例:
#include <iostream>
#include <string>
using namespace std;
struct Student{
char name[10];
int num;
char sex;
}
int main()
{
Student *p;
p=new Student;//空间大小由Student类型自动赋值
strcpy(p->name,"Wang Fun");//用p访问结构体变量
p->num=10123;
p->sex='M';
cout<<p->name<<" "<<p->num<<" "<<p->sex<<endl;
delete p;//释放空间
return 0;
}