String字符串:
C++的标准库中,提供了一种用来表示字符串的数据类型string,这种类型能够表示长度可变的字符序列。使用它必须包含string头文件
定义和初始化:
1
2
3
4
5
6
7
8
9
10// 默认初始化,空字符串
string s1;
// 用另一个字符串变量,做拷贝初始化
string s2 = s1;
// 用一个字符串字面值,做拷贝初始化
string s3 = "Hello World!";
// 用一个字符串字面值,做直接初始化
string s4("hello world");
// 定义字符和重复的次数,做直接初始化,得到 hhhhhhhh
string s5(8, 'h');处理字符串中的字符:
1
2
3
4
5
6
7
8
9string str = "hello world";
// 获取第3个字符
cout << "str[2] = " << str[2] << endl;
// 将第1个字符改为'H'
str[0] = 'H';
// 将最后一个字符改为'D'
str[str.size() - 1] = 'D';
cout << "str = " << str << endl;字符串相加:
1
2
3
4
5
6// 字符串相加
string str1 = "hello", str2("world");
string str3 = str1 + str2; //str3 = "helloworld"
string str4 = str1 + "," + str2 + "!";//str4 = "hello,world!"
//string str5 = "hello," + "world!";//错误,不能将两个字符串字面值相加比较字符串:
1
2
3
4
5
6
7str1 = "hello";
str2 = "hello world!";
str3 = "hehehe";
str1 == str2; // false
str1 < str2; // true
str1 >= str3; // true- 如果两个字符串长度相同,每个位置包含的字符也都相同,那么两者“相等”;否则“不相等”;
 - 如果两个字符串长度不同,而较短的字符串每个字符都跟较长字符串对应位置字符相同,那么较短字符串“小于”较长字符串;
 - 如果两个字符串在某一位置上开始不同,那么就比较这两个字符的ASCII码,比较结果就代表两个字符串的大小关系
 
引用:(&)
在做声明时,可以在变量名前加上“&”符号,表示它是另一个变量的引用。引用必须被初始化。
1
2
3
4
5
6
7int a = 10;
int& ref = a; // ref是a的引用
//int& ref2; // 错误,引用必须初始化
cout << "ref = " << ref << endl; // ref等于a的值
cout << "a的地址为:" << &a << endl;
cout << "ref的地址为:" << &ref << endl;// ref和a的地址完全一样引用本质上就是一个“别名”,它本身不是数据对象,所以本身不会存储数据,而是和初始值“绑定”(bind)在一起,绑定之后就不能再绑定别的对象了。
定义了应用之后,对引用做的所有操作,就像直接操作绑定的原始变量一样。所以,引用也是一种间接访问数据对象的方式。
1
2
3
4
5
6
7
8
9
10ref = 20; // 更改ref相当于更改a
cout << "a = " << a << endl;//a=20
int b = 26;
ref = b; // ref没有绑定b,而是把b的值赋给了ref绑定的a
cout << "a的地址为:" << &a << endl;
cout << "b的地址为:" << &b << endl;
cout << "ref的地址为:" << &ref << endl;
cout << "a = " << a << endl;当然,既然是别名,那么根据这个别名再另起一个别名也是可以的:
1
2
3
4
5
6// 引用的引用 地址都是一样的
int& rref = ref;
cout << "rref = " << rref << endl;
cout << "a的地址为:" << &a << endl;
cout << "ref的地址为:" << &ref << endl;
cout << "rref的地址为:" << &rref << endl;“引用的引用”,是把引用作为另一个引用的初始值,其实就是给原来绑定的对象又绑定了一个别名,这两个引用绑定的是同一个对象。
注意:引用只能绑定到对象上,而不能跟字面值常量绑定;也就是说,不能把一个字面值直接作为初始值赋给一个引用。而且,引用本身的类型必须跟绑定的对象类型一致。
1
2
3//int& ref2 = 10; // 错误,不能创建字面值的引用
double d = 3.14;
//int& ref3 = d; // 错误,引用类型和原数据对象类型必须一致
内联函数:
内联函数是C++为了提高运行速度做的一项优化
定义内联函数,只需要在函数声明或者函数定义前加上inline关键字
1
2
3
4
5//内联函数
inline const string& longerStr(const string& str1, const string& str2)
{
return str1.size() > str2.size() ? str1 : str2;
}内联仅仅只是给编译器一个建议,编译器不一定会接受这种建议,如果你没有将函数声明为内联函数,那么编译器也可能将此函数做内联编译。一个好的编译器将会内联小的、简单的函数
默认参数:
c++在声明函数原型的时可为一个或者多个参数指定默认(缺省)的参数值,当函数调用的时候如果没有指定这个值,编译器会自动用默认值代替
1
2
3
4
5
6
7
8// 默认实参
string stuInfo(string name = "", int age = 18, double score = 60)
{
string info = "学生姓名:" + name + "\t年龄:" +
to_string(age) + "\t平均成绩:" + to_string(score);
return info;
}注意:一旦某个形参被定义了默认实参,那它后面的所有形参都必须是默认实参。也就是说,所有默认实参的指定,应该在形参列表的末尾。
1
2
3
4// 错误,默认实参不在形参列表末尾
//string stuInfo(string name = "", int age = 18, double score);
// 正确,可以前面的形参没有默认实参
string stuInfo(string name, int age = 18, double score = 60);也可以在声明的时候定义实参:
1
2
3
4
5
6
7
8
9
10
11
12void Fun(char a='x',int b=66);
int main(void)
{
cout << "hello world" << endl;
Fun();
return 0;
}
void Fun(char a,int b)
{
cout << "a:" << a << endl;
cout << "b:" << b << endl;
}默认实参定义时要优先放到形参列表的尾部;而调用时,只能省略尾部的参数,不能跳过前面的形参给后面传值。
1
2
3
4
5
6
7cout << stuInfo() << endl; // "",18, 60.0
cout << stuInfo("张三") << endl; // "张三",18, 60.0
cout << stuInfo("李四", 20) << endl; // "李四",20, 60.0
cout << stuInfo("王五", 22, 85.5) << endl;// "王五",22, 85.5
//cout << stuInfo(19, 92.5) << endl;// 错误,不能跳过前面的形参给后面传值
//cout << stuInfo(, , 59.5) << endl;// 错误,只能省略末尾的形参注意点:
- 注意函数与重载的二义性。
 - 函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数。
 - 如果函数声明和函数定义分开写,函数声明和函数定义不能同时设置默认参数。
 
占位参数:
c++在声明函数时,可以设置占位参数。占位参数只有参数类型声明,而没有参数名声明。一般情况下,在函数体内部无法使用占位参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21void Fun(char ,int ,float );//只有类型,没有变量名
void Fun(char a,int b,float c,char);
int main(void)
{
cout << "hello world" << endl;
Fun('a',1,1.1);
Fun('b',2,2.2,'3');
return 0;
}
void Fun(char a,int b,float c)
{
cout << "a1:" << a << endl;
cout << "b1:" << b << endl;
cout << "c1:" << c << endl;
}
void Fun(char a,int b,float c,char)
{
cout << "a2:" << a << endl;
cout << "b2:" << b << endl;
cout << "c3:" << c << endl;
}注意:占位参数也可以指定缺省值
函数重载:
在C++中,同一作用域下,同一个函数名是可以定义多次的,前提是形参列表不同(参数类型、数量或顺序不同)。这种名字相同但形参列表不同的函数,叫做“重载函数”。
1
2
3
4
5
6
7
8void func(){}
void func(int x){}
void func(int x,char y){}
//经过 g++编译环节之后
_Z7funcv //v 代表 void,无参数
_Z7funci //i 代表参数为 int 类型
_Z7funcic //i 代表第一个参数为 int 类型,第二个参数为 char 类型
extern “C”:
以下在 Linux 下测试:
c 函数: void MyFunc(){} ,被编译成函数: MyFunc
c++函数: void MyFunc(){},被编译成函数: _Z7Myfuncv
通过这个测试,由于 c++中需要支持函数重载,所以 c 和 c++中对同一个函数经过编译后生成的函数名是不相同的,这就导致了一个问题,如果在 c++中调用一个使用 c 语言编写模块中的某个函数,那么 c++是根据 c++的名称修饰方式来查找并链接这个函数,那么就会发生链接错误,以上例,
c++中调用 MyFunc 函数,在链接阶段会去找 _Z7Myfuncv,结果是没有找到的,因为这个 MyFunc 函数是 c 语言编写的,生成的符号是 MyFunc。
那么如果我想在 c++调用 c 的函数怎么办?
- extern “C”的主要作用就是为了实现 c++代码能够调用其他 c 语言代码。
 - 加上 extern “C”后,这部分代码编译器按 c 语言的方式进行编译和链接,而不是按 c++的方式。
 
1  | 
  |