C++(从C到C++)
学习目标
为什么学C++?
(1) C++是面向对象编程,更注重大局观(架构),忽视细节,是一种新的编程方式,适合大型软件项目。
(2) Qt使用的语言是C++,Qt是整个学习阶段唯一的上位机图形用户界面开发框架。
C++简介:、
1.C++发展史
1983年,贝尔实验室(Bell Labs)的Bjarne Stroustrup发明了C++。 C++在C语言的基础上进行了扩充和完善,是一种面向对象程序设计(OOP)语言。
Stroustrup说:“这个名字象征着源自于C语言变化的自然演进”。还处于发展完善阶段时被称为“new C”,之后被称为“C with Class”。C++被视为C语言的上层结构,1983年Rick Mascitti建议使用C++这个名字,就是源于C语言中的“++”操作符(变量自增)。而且在共同的命名约定中,使用“+”以表示增强的程序。
常用于系统开发,引擎开发、嵌入式开发等应用领域, 至今仍然是最受广大程序员喜爱的编程语言之一。
2.C++特点
(1)在支持C的基础上,全面支持面向对象编程
(2)编程领域广泛,功能强大(最强大的编程语言,没有之一)
(3)标准保持更新,目前常用的基础标准为ISO C++98标准、ISO C++11标准等
(4)为数不多的支持底层操作的面向对象语言
(5)在面向对象的语言中执行效率极高
3.面向对象思想
面向对象编程的核心思想可以概括为:将数据(属性)和操作数据的方法(行为)封装在对象中,通过对象之间的交互来完成任务。这种思想使得程序更加模块化、易于维护和扩展。
面向对象编程(OOP)
OOP是程序设计工程化的一种方法,软件架构的一种思想。
OOP基本原则是程序是由单个能够起到子程序作用的单元或对象组合而成,以达到软件工程的三个主要目标:重用性、灵活性和扩展性。
面向过程是以“怎么解决问题”为核心,而面向对象思想在于“谁来解决问题”为核心。
4.环境安装
可以找一下这个版本下载,内存比较大,网盘放不下了。
(1)C++本身不支持中文,但是可通过特殊的设定使开发环境支持中文输出:
(2)设置完成关闭Qt Creator,重新进入就可以使用了。
(3)创建并运行第一个程序的操作步骤如下:
1. 启动Qt Creator
2. 点击
3. 在弹出的窗口中,按照下图所示进行操作。
4.项目存放路径自己找个合适的位置方就行,不要有中文名,其他都点下一步就行
5.创建好后,在根目录有一个.pro 文件,早最后一行加上下面这句,目的是让项目使用C++11版本的环境,其他文件都不动,除了主函数文件和创建的其他文件(头文件),但是一个项目中只有一个主函数,所以不要创建多个.cpp文件。
QMAKE_CXXFLAGS += -std=c++11
6.编写号代码后点击右下角就可以运行了,编译是和运行一起的。
基本格式
#include <iostream>using namespace std;int main()
{cout << "hello" << endl;return 0;
}
与C语言的不同:
1.c++的头文件是不带.h的
2.在头文件后添加using namespace std;
为什么使用这句话:
(1).命名空间(Namespace)的核心作用
命名空间是 C++ 用于避免命名冲突的机制。标准库的所有内容都定义在
std
命名空间中。(2).简化代码编写
没有
using namespace std;
时,必须使用完整限定名:std::cout << "Hello"; std::cin >> value; std::vector<int> nums;
基本使用:
1.输入输出
头文件:#include <iostream>
使用cin输入,cout输出,大小于号箭头指向方向就是输入和输出方向,
(1)输入是从终端输入到变量中,所以此时指向变量。
(2)输出是从变量输出到终端,所以此时是指向终端cout。
#include <iostream>using namespace std;int main()
{int a = 1;int b;cin >> b; //向b输入内容cout << a << " " << b << endl; //输出变量cout << "hello world" << endl; //输出常量return 0;
}
2.引用
(1)引用是一种简化指针,应用相当于给变量或别的常量起的的别名
int a = 10;int &b = a; //b是a的引用
(2)声明引用的时候,必须初始化(定义的时候就得确定是对哪个变量的引用)
int a = 10;int &b; //错误
(3)改变别名的数值,原变量的值也会变
int a = 10;int &b = a;b = 90; //a和b都变成90
(4)一旦定义了这个“别名”,就不能再次成为其他变量的引用(只能当第一次定义的时候代表的变量或者和常量的别名)
int a = 10;int b = 90;int &c = a; //c已经是a的别名c = b; //错误
3.初始化
初始化变量应该都很熟悉,C++初始化变量和C语言有什么不同呢?基本是一样,主要不同点在于C++初始化方式比较多:
C语言的初始化方式:
int a = 10;char b = 'b';
C++可以使用的初始化方式:
//第一种:C语言式初始化int a = 10;char b = 'b';//第二种:C++初始化方式int a(10);char b('b');//第三种:C++11版本新增初始化方式int a{10};char b{'b'};
第三种有什么好处,他会在初始化不合理的时候提示警告。
比如当我们把小数直接赋值给变量,他会提示警告和可能的运算方式(去掉小数):
int a{12.3};
4.字符串类型
C++比C语言多一个数据类型string类型,我们都知道C语言中所有数据类型都是关键字,但是string类型不是关键字,它存在于C++的库中(string),我们只导入iostream库也是可以的,因为iostream库中也包含string类型,这种情况在C语言中也存在,但是我们想使用string库的函数还是要导入string库,所以我们在使用string类型的时候,最好还是导入string库。
C++中设置这么一个数据类型的意义是什么?string类型用于在大多数的情况下替代char*类型,不用担心内存是否足够与长度多少等问题。
定义字符串类型并且实现输入输出:
#include <iostream>
#include <string>
using namespace std;int mian(){string str;cin >> str;cout << str << entl;return 0;
}
5.字符串数组
C++作为C语言的扩展,数组也是和C语言十分相似,但是注意:在C++中,数组越界不一定会立即导致段错误,其行为是未定义行为。以字符串类型为例,我们为了防止数组调用越界问题出现找不到错原因,会在数组名后面加上.at(i)。使用[]和.at(i)都可以取出单个字符。(仅限于字符串类型使用)下面就是C++越界后,不会在运行的时候报段错误,会发生未定义行为(无法确定会发生什么)。
(1)at函数更加安全,越界后终止运行
#include <iostream>using namespace std;int main(){string str;cin >> str;//for(int i < 0 ; i < str.size() ; i++){for(int i < 0 ; i < str.length() ; i++){ //.size()和.length()可以求字符串的长度(仅限于字符串)cout << str.at(i) << " ";}return 0;
}
(2)但是[]效率更高
6.循环
循环和C语言一样,但是C++11增加了两种表达方式(字符串也可以使用)
(1)常见的两种方式:
#include <iostream>using namespace std;int main (){int a[5] = {1,2,3,4,5};//遍历数组for(int i = 0 ; i < 5 ; i ++){cout << a[i] << endl;}//c++11 for-each(增强型for循环)for(int i: a){cout << i << endl;}//迭代器return 0;
}
(2)迭代器
1. 输入迭代器 (Input Iterator)
特点:只能读取元素,只能单向移动,只能遍历一次
2.输出迭代器 (Output Iterator)
特点:只能写入元素,只能单向移动,只能遍历一次
3.前向迭代器 (Forward Iterator)
特点:可读写,可多次遍历,只能单向移动
4.双向迭代器 (Bidirectional Iterator)
特点:可读写,可多次遍历,可双向移动
5.随机访问迭代器 (Random Access Iterator)
特点:功能最全,支持所有操作
重点说一下随机访问迭代器,用的最多:
#include <vector>
#include <iostream>using namespace std;int main() {vector<int> nums = {5, 2, 8, 1, 9}; //创建容器// 随机访问迭代器auto it = nums.begin(); //访问容器第一个元素//循环访问for(auto cit = nums.begin() ; cit != nums.end() ; ++cit){cout << *cit << endl;}// 随机访问cout << "第三个元素: " << it[2] << endl; // 输出8// 算术运算,访问中间元素auto middle = it + nums.size() / 2;cout << "中间元素: " << *middle << endl;return 0;
}
7.函数
7.1内联函数 inline
C++中引入内联函数的目的是为了取代C语言中宏定义函数;
在函数类型前面加上关键字inline,就会在编译的时候把函数中语句放在主函数中,这样就会运行更快,相反编译的时候就会变慢,牺牲编译速度换取运行速度,消除调用函数的额外开销、
但是编译器一般只把长度小于5行的函数放入主函数编译,太长,编译器会觉得不合适就不会这样操作,比如递归多次的函数,很长的循环函数。
#include <iostream>using namespace std;inline void test()
{int a = 1;int b = 2;cout << a+b << endl;cout << a-b << endl;
}inline void test2() // 定义
{int a = 1;int b = 2;cout << a*b << endl;cout << a/b << endl;
}int main()
{test();/*int a = 1; //编译的时候会替换成这样int b = 2;cout << a+b << endl;cout << a-b << endl;*/test2();/*int a = 1;int b = 2;cout << a*b << endl;cout << a/b << endl;*/return 0;
}
7.2函数重载
函数签名:函数的标志,包含三个部分(函数名称,参数个数和参数类型),在C++中我们认定只要三部分都一样,我们才认定两个函数重复。
由此可见,在C++中,是允许函数名字一样的,只有当三部分一致,才会认定函数重复,才会报错
#include <iostream>using namespace std;void print()
{cout << "A" << endl;
}
void print(int a)
{cout << "B" << a << endl;
}
void print(string s)
{cout << "C" << s << endl;
}
//int print() 错误:二义性
//{
// cout << "A" << endl;
// return 1;
//}int main()
{print();print("dfsfd");print(23);return 0;
}
7.3参数默认(缺省)值
(1)在C++中允许给函数的参数设定默认值,调用的时候传入参数会从最左边开始一个个替换参数。
(3)函数声明和定义分离的时候,参数默认值只能写一次,不能声明和定义的函数参数内都声明默认值。
(2)刚开始学C++不要把参数默认值和函数重载一起使用,容易错乱。
#include <iostream>using namespace std;void print(int a = 1,int b = 2,int c = 3)
{cout << a << b << c << endl;
}
void test(int a); //函数声明
void test(int a = 1) //函数定义
{cout << a << endl;
}
void func1(string s1,string s2,string s3="AAA")
{cout << s1 << s2 << s3 << endl;
}
void func2(string s1,string s2="AAA",string s3="BBB")
{cout << s1 << s2 << s3 << endl;
}
int main()
{
//从左开始替换形参print(); // 123print(6); // 623print(6,6); // 663print(6,6,6); // 666test(); // 1func1("1","2");func1("1","2","3");func2("1");func2("1","2");func2("1","2","3");return 0;
}
7.4哑元函数
一个函数只有类型没有名字,这个特殊的参数就是哑元,这样的函数叫做哑元函数。
使用哑元函数的目的:
1.可以使用这个参数强行重载函数
2.保持函数的向前兼容性,什么是向前兼容性?如果后期做大项目,主函数调用了一个函数上百次,如果你要优化函数,简化掉了一个参数,如果去掉参数,所有函数调用都要找到更改十分麻烦,使用哑元函数就可以解决,只改函数,把不用的参数无效化就可以了。
#include <iostream>using namespace std;
/*
void add(int a,int b){ //原型cout << a + b <<endl;
}
*/
void add(int a,int){ //哑元函数cout << a <<endl;
}int main()
{add(8,9); //会把后面的参数无效化return 0;
}