1.C++的输入输出
掌握一门新语言第一步肯定是先搞出来Hello world!那C++是怎样做的呢。
#include <iostream>
using namespace std;
int main() {
cout << "Hello world!!!" << endl;
return 0;
}
1. 使用cout标准输出和cin标准输入时,必须包含< iostream >头文件以及std标准命名空间。早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h。
2.C++输入输出更方便,不需增加数据格式控制,%d %f .....
2.字符串变量
在C中我们是这样初始化的。
char str [] = "hello";
char* str = "hello";
不过一个是动态开辟的数组,另一个是在字符常量区不可以被修改
在C++种引入了一个新的数据类型 string类型,我们就可以这样做
#include <iostream>
#include <string>
//要引入这个头文件
using namespace std;
int main() {
string str = "hello";
return 0;
}
3.引用
3.1概念
引用不是新建一个变量,而是给已存在的变量起一个别名,编译器不会给他开辟内存空间,他和他的引用变量共用一个内存空间。张三,他也可以被叫做法外狂徒
#include <iostream>
using namespace std;
int main() {
int a = 0;
int& b = a;
}
这里的b就是a的一个别名,引用类型必须和引用实体是同种类型的!!
3.2引用特性
- 用引用的时候必须初始化。
- 一个变量可以有多个引用。
- 引用一旦引用一个实体,再不能引用其他实体,这个在底下会分析。
可以清晰的看得到就是用的一个内存空间
3.3引用本质
引用的本质是一个指针常量
char* const str = NULL;
//这是指针常量,指向的目标不可改变!
char const* str = NULL;
//这是常量指针,是指针指向的变量不可以通过指针来修改!
这时候我们在详细的解释一下引用特性的第三点一旦引用一个实体再不能引用其他实体。
3.4常引用
#include <iostream>
using namespace std;
int main() {
int a = 10;
//int& b = 10;
//会报错引用必须引用一块合法的内存
//这个10在常量区,并不在堆和栈上。
const int& b = 10;
//编译器内部修改了
//int temp = 10;
//const int &b = temp;
//b = 20 也是报错的加上const之后不可被修改了
}
常引用让代码的可读性提高明确的告诉说这个已经不可以被修改了!
3.5做函数参数
之前学c的时候就写过一个swap函数来交换两个函数的值,用的是址传递(扯一嘴值传递,也就是形参实参这个 ,在函数调用的时候会发生临时拷贝形成形参,这个跟实参完全不是一个东西你可以把他的地址打印出来看看,这个是一个局部变量在栈帧上面,函数调用结束后栈帧释放,局部变量的生命周期就到这块了,所以你值传递的时候,回来发现并没有交换)我们也刚刚知道了引用的本质是一个常量指针所以就跟址传递有异曲同工之妙。
#include <iostream>
using namespace std;
void swap(int& a, int& b) {
int temp = a;
a = b;b = temp;
}
int main() {
int a = 10;
int b = 20;
cout << "before:" << a <<" " << b << endl;
swap(a, b);
cout << "after:" << a <<" "<< b << endl;
return 0;
}
3.6做函数返回值
1.不要返回局部变量的引用(vs2022 更改了)
#include <iostream>
using namespace std;
int& text () {
int a = 10;
return a;
}
int main() {
int& aa = text();
cout << aa << endl;
cout << aa << endl;
}
不是局部变量,应该在函数调用结束之后,应该释放了吗?第一次的值是正确的是因为编译器做了保留,第二次的值是错误的是因为已经释放了。
很有意思的是在vs2022的MSVC编译器下竟然给过了而且两次都是10,应该已经做了优化。
那就换个环境在gcc下看看,这里用的编译器是mingw32比较老的版本。
这块就报错了说 对局部变量"a"的引用返回
2.可以作左值
因为返回值是a的引用,赋值更改变量内容,也就是通过指针修改引用是一个常量指针不是指针常量所以是可行的。
4.函数重载
在日常生活中,一个词可以有多个意思,人们可以通过联系上下文在结合语境来判断这个词的语意,这个时候我们认为这个词被重载了。
4.1函数重载的概念
这个是函数的一种特殊情况,C++允许在同一作用域下声明几个功能相似的同名函数,这些同名函数的形参列表 类型 顺序 参数个数 必须不同,常用来处理实现功能类似但是数据类型不同的问题。
举个课本上的例子吧
#include <iostream>
using namespace std;
void max(int a)
{
cout << "count max" << endl;
}
void max(int a,double b)
{
cout << "order1 max" << endl;
}
void max(double a,int b)
{
cout << "order2 max" << endl;
}
void max(int a,int b)
{
cout << "int max" << endl;
}
void max(double a, double c)
{
cout << "double max" << endl;
}
void max(char a, char b)
{
cout << "char max" << endl;
}
int main()
{
int a = 0, b = 0;
double c = 0.0, d = 0.0;
char e = 0, f = 0;
max(1);
max(a,c);
max(c,a);
max(a,b);
max(c,d);
max(e,f);
}
调用这三次max函数每次根据传入的实参的类型不同,系统找到与之相应的入口参数进行匹配从而实现一个函数多种用途,也就是我们的重载。所以我们根据以上例子就可以得出函数重载的条件:
- 必须在同一个作用域下。
- 函数名相同。
- 参数数据类型不同,个数不同,顺序不同。
4.2特殊问题
4.2.1函数返回值作为重载条件
在函数重载中,函数返回类型不可以作为函数重载的条件,也就是不可以根据函数返回值不同来进行重载。
那么是为啥呢? 来看这段代码
#include <iostream>
using namespace std;
void max(char a, char b)
{
cout << "char max " << endl;
}
int max(char a,char b)
{
cout << "char max" << endl;
}
int main()
{
char e = 0, f = 0;
max(e,f);
}
我的入口参数都是 char呀那我该调哪个函数呢?这时候就8行了!系统无法匹配与之对应的函数,所以返回类型不能作为函数重载的条件!
4.2.2引用作为函数重载条件
1.首先引用是可以作为函数重载的条件的,在以下代码中那是怎样调用的呢?
#include <iostream>
using namespace std;
void max(int& a) {
cout << "max(&a)" << endl;
}
void max(const int& a) {
cout << "max(const &a)" << endl;
}
int main() {
int a = 10;
max(a);
}
这两个max函数就是入口参数不同符合函数重载的条件那调取那个呢?
F5运行之后发现是第一个因为a是一个变量有自己开辟的空间,还有自己的内容可以读取也可以写入,const 限定了你这个只能读不能写,是不可以修改的,所以调取的是第一个。
第二个也是可以调取的只需要传入一个常量就好了 max(10);
如果是第一个函数的话 传入就成了 int & a = 10;这样是不被允许的 要引用的话一定是一个合法的内存空间要不是在栈上要不是在堆上,而这个10 在常量区里面的,上文也说到了加上const的话编译器就会认为是
int temp = 10;const int &a = temp;
就是合法的。