二、从C到C++
本章介绍一些C++拓展的非面向对象功能。
- 引用(掌握)
1.1 概念
引用从一定程度上讲是一个指针的平替,几乎被所有面向对象编程语言所使用。引用相当于对某一个目标变量起”别名“。
操作引用与操作原变量完全一样。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
// b是a的引用
int &b = a;
cout << a << " " << &a << endl; //1 0x61fe88
cout << b << " " << &b << endl; //1 0x61fe88
return 0;
}
1.2 引用的性质
- 可以改变引用的值,但是不能再次成为其他变量引用。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
// b是a的引用
int &b = a;
int c = 3;
b = c; // 3 只是赋值,不是引用,b还是a的引用
cout << a << " " << &a << endl; //3 0x61fe88
cout << b << " " << &b << endl; //3 0x61fe88
cout << c << " " << &c << endl; //3 0x61fe84
return 0;
}
- 声明引用的时候,必须要初始化。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
// int &b; // 错误 引用必须要初始化。
cout << a << " " << &a << endl; //3 0x61fe88
return 0;
}
- 声明引用的时候,不能初始化为null
#include <iostream>
using namespace std;
int main()
{
int a = 1;
// int &b = nullptr; // 错误引用不能初始化为null
// int &b = null;
cout << a << " " << &a << endl; //3 0x61fe88
return 0;
}
- 声明引用的时候,初始化的值可以是纯数值,但是此时要用const关键字修饰引用,表示该引用为常量引用,这样引用的值不可变。
#include <iostream>
using namespace std;
int main()
{
const int &a = 1; // 常量引用
// a = 2; // 错误常量引用的数值不能被改变
cout << a << " " << &a << endl; //3 0x61fe88
return 0;
}
- 可以将变量引用的地址赋值 给一个指针,此时指针指向的还是原来的变量。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
int &b = a;
int *c = &b;
cout << a << " " << &a << endl; // 1 0x61fe84
cout << b << " " << &b << endl; // 1 0x61fe84
cout << *c << " " << c << endl; // 1 0x61fe84
return 0;
}
- 可以使用const修饰引用,此时如果原变量的值改变了,引用的值也会改变。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
const int &b = a;
a++;
// b++; // 错误的,b是只读的
cout << a << " " << &a << endl; // 2 0x61fe84
cout << b << " " << &b << endl; // 2 0x61fe84
return 0;
}
1.3 引用的参数
写一个函数,函数有两个参数a和b,函数 的功能是交换两个传入的参数【原来】变量的值。
#include<iostream>
#include <string.h>
using namespace std;
// 只是test1内部进行相互交换了
// 不符合需求
void test1(int a,int b)
{
int t = a;
a = b;
b = t;
}
// C语言的指针
void test2(int *a,int *b)
{
*a = *a^*b;
*b = *a^*b;
*a = *a^*b;
}
// C++ 编程方式
void test3(int &a,int &b)
{
a = a^b;
b = a^b;
a = a^b;
}
int main()
{
int a = 1;
int b = 2;
test3(a,b);
cout << a << endl;
cout << b << endl;
return 0;
}
引用作为参数进行定义的时候,在参数传递时,是不会产生副本的,这样会提高运行效率,我们在正常编程中,建议使用引用作为参数进行传递。
引用参数,在不参与计算的情况,我们建议使用const进行修饰。以达到引用安全的目的。
- 赋值(熟悉)
通常编程当中使用=进行赋值操作,C++新增了新的赋值语法。
#include<iostream>
#include <string.h>
using namespace std;
int main()
{
int a(1); // int a = 1;
cout << a << endl;
int b(a); // int b = a;
cout << b << endl;
int c(a+b); // int c = a + b;
cout << c << endl; // 2
return 0;
}
C++11里对上述写法又进行了升级
#include<iostream>
#include <string.h>
using namespace std;
int main()
{
double b = 3.14;
int b1 = b;
int b2(b);
int b3{b}; // C++11新增的 对数据窄化做出警告
cout << b1 << endl; // 3 数据窄化
cout << b2 << endl; // 3 数据窄化
cout << b3 << endl; // 3 数据窄化
return 0;
}
- 键盘输入(掌握)
可以使用cin把用户在命令行中输入的内容赋值到变量中。
cin与cout一样,都属于头文件iostream中标准输入输出流。
#include<iostream>
#include <string.h>
using namespace std;
int main()
{
int a;
// C++ 的字符串是string
string str;
cout << "请输入一个数字和字符串:" << endl;
cin >> a >> str ; // 接收键盘输入:一个整数和一个字符串,可以连续输入。
cout << a << endl;
cout << str << endl;
return 0;
}
- string 字符串类(掌握)
string 不是C++的基本数据类型,他是一个C++标准库中的字符串类,使用时需要引入头文件,#include<string>,而不是string.h
string在绝大多数情况下,可以替代C语言中字符串,不必担心内存是否足够,和字符串长度等,其中内部还包含了很多字符串处理函数,可以完成各种情况下的字符串处理功能。
string和C语言相同,字符串编码使用ASCII编码,不支持中文。
#include<iostream>
using namespace std;
int main()
{
string str = "helloworld";
cout << str.size() << endl; // 10字符串长度
cout << str.length() << endl; // 10字符串长度
cout << str[1] << endl; // e
cout << str.at(5) << endl; // w
return 0;
}
两种方式都可以,但是在C++中更推荐你使用at函数。原因时at函数更加安全。at函数的运行效率慢。[ ]效率更高。
#include<iostream>
using namespace std;
int main()
{
string str = "helloworld";
cout << str.size() << endl; // 10字符串长度
cout << str.length() << endl; // 10字符串长度
// cout << str[100] << endl; // 什么都不输出,也不报错,不安全
cout << str.at(100) << endl; // 安全的,越界会报异常。
return 0;
}
string 类支持多种遍历方式
- 普通循环(for循环)
- for each循环 C++11
#include<iostream>
using namespace std;
int main()
{
string str = "helloworld";
// 以for循环的方式遍历输出字符串
for(int i = 0; i <str.size(); i++)
{
cout << str.at(i);
}
cout << endl;
// for each的方式进行循环遍历字符串
for(char i : str)
{
cout <<i;
}
return 0;
}
- 函数
5.1 内联函数(掌握)
内联函数用于取代C语言中宏定义的函数。内联函数的正确使用可以提升程序的执行效率。内联函数在编译的时候,直接把函数体展开到主函数中编译,在运行期间可以减少调用的开销。(以空间换时间)
通常将具有以下性质的函数写为内联函数:
- 代码长度5行以内。
- 不能包含复杂的控制语句。
- 被频繁调用
#include<iostream>
using namespace std;
// 声明成-内联函数
inline void show(string str)
{
cout << str << endl;
}
int main()
{
show("nihao");
return 0;
}
内联函数关键字:inline
后续学习的成员函数都默认添加了inline修饰。
但是我们手动添加的inline关键字,将函数声明称内联函数。这个不是我们能决定的。我们只是给编译器提一个建议,编译器有自己的判断准则。具体是否能变成内联函数,还是编译器自己决定的。
5.2 函数重载 overload(重点)
C++中允许多个函数使用同一个名称,这种写法就是函数重载。函数重载要求函数名称相同,但是参数不同(类型或者数量)或者前后顺序不同。与返回值和其他因素无关。
#include <iostream>
using namespace std;
void print_show(int i,double d)
{
cout << "调用了int重载" << i << endl;
}
//void print_show(double d)
//{
// cout << "调用了double重载" << d << endl;
//}
//void print_show(float f)
//{
// cout << "调用了float重载" << f << endl;
//}
void print_show(string str)
{
cout << "调用了string重载" << str << endl;
}
int main()
{
print_show(6,5.4);
return 0;
}
5.4 哑元函数(熟悉)
函数的参数只有类型,没有名称,有这样的参数的函数就是哑元函数。
#include <iostream>
using namespace std;
// 哑元函数
void print_show(int)
{
cout << "调用了int重载" << endl;
}
void print_show(string str)
{
cout << "调用了string重载" << str << endl;
}
int main()
{
print_show(6); // 尽管函数内不用参数,但是还是需要传递参数
return 0;
}
作用1:哑元函数用来区分函数重载。
作用2:运算符重载中会用到。
#include <iostream>
using namespace std;
// 哑元函数
void print_show(int i,int)
{
cout << "调用了int1重载" << endl;
}
void print_show(int i)
{
cout << "调用了int2重载" << endl;
}
void print_show(string str)
{
cout << "调用了string重载" << str << endl;
}
int main()
{
print_show(6,1); // 尽管函数内不用参数,但是还是需要传递参数
return 0;
}