1.介绍c++
C++头文件风格
c++ 老风格:以.h结尾 是c语言风格 stdio.h (尽量不)
c++的转换风格: 去掉.h 在文件名前加c 例如#include <cstdio>
c++ 新风格 :没有拓展名 直接文件名,#include <iostream>
2.c++ 的开发环境
1. visual studio 2018
2. qt creator 5.3
3. g++ 开发环境
第一步.安装g++ ,sudo apt-get install g++
第二步. 编写.cpp的代码
第三步: g++ xxx.cpp -o abc
3.基本输入输出
1. 标准输出 cout
格式: cout << "字符串" << 变量 << 变量 << endl;
注意: endl是换行,可以放中间和末尾
c++的输出是流的方式实现是(stream)
在定义对象时,系统会在内存中开辟一段缓存,用来存放输入输出流的数据,缓冲区满或者遇到endl后或者flush后才会输出。
需要头文件 #include <iostream>
cout是一个变量(是输出流的对象)
2.格式化输出 (不是重点)
第一种方式: setf成员函数,cout的成员函数。
fmtflags setf(fmtflags __fmtfl)
作用: 对输出的内容做格式化处理
参数: __fmtfl 是需要格式化处理的状态
比如: ios_base::showbase 显示进制的前缀
fmtflags setf(fmtflags __fmtfl, fmtflags __mask)
作用: 对输出的内容做格式化处理
参数: __fmtfl 是需要格式化处理的状态
__mask 需要取消的状态位
案例:cout. setf(ios_base::hex,ios_base::basefield);
综合案例: 设置宽度 和设置对齐方式
cout.width(宽度);
设置右对齐方式 (setf函数,需要使用两个参数的版本,第一个参数ios_base::right,第二个参数是 ios_base::adjustfield )
第二种方式: cout的成员函数 例如 width( )
第三种方式:setiosflags函数 ( 笔记的方式发给大家--自行学习)
setiosflags 是包含在命名空间iomanip 中的C++ 操作符,该操作符的作用是执行由有参数指定。
区域内的动作;
3.标准输入
关键字:cin
格式: cin >> 变量1 >> 变量2 ;
注意: cin也是一个对象,暂时理解成结构体变量
等价于 scanf
不可以加字符串 endl
cin可以识别基本数据类型。int double float short long
输入两个整形,计算他们的模,输出。
4.标准错误
关键字:cerr
格式:cerr << "字符串" << 变量 <<endl;
注意: cerr是没有缓冲的,数据会立马输出
一般是遇到错误,需要立马打印出来的场景
5.标准日志:
关键字: clog
格 式: clog << "字符串" << 变量 <<endl;
注 意: 有缓冲,和cout的使用一样
需要打印日志的时候需要
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int c;
cout<< "我的名字:"<<"she001"<<endl<<"今年:18岁"<< endl;
int x=0x123;
//cout.setf(ios_base::hex,ios_base::basefield);//设置输出为十六进制
//cout.setf(ios_base::oct,ios_base::basefield);//设置输出为八进制
//cout.setf(ios_base::dec,ios_base::basefield);//设置输出为十进制
//cout.setf(ios_base::showbase);//设置为标准输出,加上 0x
//cout<<"x="<<x<<endl;//标准输入
//cout.width(10);//设置输出的数据 宽度为10
//cout.setf(ios_base::right,ios_base::adjustfield);//设置右对齐
//cout<<x<<endl;
///标准输入 展示理解为结构体变量
//关键字: cin
//注意 : cin 也是一个对象
//等价于scanf
//cin 可以识别基本数据类型 int double float short long
//
//
//
// 练习 输入两个变量 取膜
//int a,b;
// cin>>a>>b;
// int d= a%b;
// cout<<d<<endl;
//
///标准错误
//关键字:cerr
//格式:cerr <<"字符串"<<"变量"<<endl;
//无缓冲
cerr<<"我的错误"<<x<<endl;
//标准日志
//关键字 clog
//格式 clog<< " 字符串"<<"变量"<<endl;
//注意 :有缓冲 和cout 的使用一样 .
// 打印的时侯需要
//clog<<"casda"<<x<<endl;
return 0;
}
4.名字空间
1. 前奏: using namespace std; 名字空间std
为什么要名字空间;
防止命名冲突,提供作用域。
模块化编程,提高效率
2.定义名字空间
格式:namespace 名字空间名 { 定义变量; 定义函数;};
注意: 在同一个作用域内,不可以有相同的名字空间名
3.名字空间可以使用的内容
可以定义变量
可以定义结构体
可以定义常量
可以定义函数
可以定义名字空间
可以定义枚举
4.案例
namespace huaqing{
int danny = 12;
const long num = 20;
struct stu { int age ; };
void fun(int a) { std::cout << "fun函数"<<std::endl; }
enum week {mon,tue};
}
6.名字空间的使用
全部引入: using namespace 名称;
部分引入: using 名称::成员
域 限 定 : 名称::成员
//全部引入:说明接下来的变量如果找不到就是在huaqing的作用域中的。
using namespace huaqing;
//部分引入:只是用stu中的y
using stu::y;
int main(){
x = 123;
fun(y);
stu::area(1,2);
struct huaqing::stu danny = {123};
cout << "age = " <<danny.age <<endl;
}
7.名字空间嵌套
格式: namespace 名字空间1
{
namespace 名字空间2{ 代码};
}
使用:
第一种: using namespace 名字空间1;
名字空间2::变量 = 123;
变量 = 123;
第二种:using namespace 名字空间1:: 名字空间2
变量 = 234; //属于名字空间2中的
名字空间1:: 变量
第三种:名字空间1::名字空间2::变量 = 123;
8.名字空间别名
格式:namespace 别名 = 名字空间名
例如: namespace abc = huaqing::danny
using namespace abc;
代码:
#include<iostream>
using namespace std;
//定义名字空间 需要 定义两个变量 int x,y
//写两个函数 .计算点x ,y 和的三角形的面积
namespace huaqing
{
int danny =12;
const long num=23;
struct stu
{
int age;
};
//定义函数
void fun(int a)
{
std::cout<<"fun函数"<<endl;
}
enum week//枚举
{
mon,
tue
};
namespace hh
{
void ll()
{
cout<<"dasdasd"<<endl;
}
}
};
namespace gw
{
int ss(int x,int y)
{
int c=x*y/2;
return c;
}
};
using namespace gw;//说明数据找不到,就到gw 里面去找
int main()
{
int gg=ss(2,2);
cout<<gg<<endl;
huaqing::hh::ll();
return 0;
}
5.内联函数
1.作用: 在c语言中,函数调用开销。使用频繁的函数开销更大,c++提供了内联函数,直接把函数内容进行复制到调用位置。
一般情况下内联是和类一起使用。
2.关键字:inline 在函数前加一个inline
3.注意事项:内联函数中代码原则上不允许超过10行。(一般5行内代码)
内联函数不允许使用循环语句和switch语句
如果函数不满足以上要求,则编译器会忽略inline关键字。
四、函数重载
1.定义:在相同的作用域下,函数名相同参数列表不同。(有两个相同函数名的函数--不会冲突),重载必须是两个及以上的函数才构成。
2.参数列表不一样:
个数不一样;
类型不一样;
顺序不一样
3.目的
减少对用户调用的复杂性,调用一个函数实现不同的效果(前人种树后人乘凉)
减少函数名的数量,避免名字空间的污染,有利于程序可读性。
注意: 返回值类型不一样不构成重载。
如果参数列表相同会构成函数的重定义错误。
const函数和非const函数构成承载(后续讲)
4.实现原理
g++编译器在编译的时候会把相同的函数名进行内部改名。对用户不可见。
改名规则: 在原本函数名前加_z3表示返回值
参数中如果是string ---->Ss
int-------->i
long -------> l
double------->d
char----------->c
float---------->f
如果有函数int fun(int a,long b,double c)编译后的函数名_z3funild
映射后的函数名 = 返回值+函数名+类型名首字母
5.匹配方式
1.精准匹配:参数列表完全匹配,不需要做任何转换。
2.提升匹配:整形提升(short-->int ,bool-->int, char--->int)
浮点型(float--->double)
3.标准转换匹配:
int--->double, double--->int
long-->double ,double--->long
int-->unsigned int;
4.省略匹配 (...) 比如printf函数。
后续会讲到操作符重载(超级重要)
代码:
#include<bits/stdc++.h>
using namespace std;
//内联函数
//作用:在c 语言 函数调用开销,使用频繁的函数开销更大, c++
//提供了内联函数,直接把函数内容进行复制调用位置
//一般情况下是和类一起使用
//
//关键字:inline 函数前面加入关键字
//注意事项:内联函数中代码,原则上不允许超过5行(不允许使用循环语句)
//如果函数不满足以上要求,则编译器会忽略 inline 关键字
//
inline int add1(int a,int b)//内联函数减少调用时间
{
return a+b;
}
//函数重载
//定义:在相同的作用域:
int add(int a,int b)
{
cout<<"int "<<endl;
return a+b;
}
int add(int a,int b,int c)
{
cout<<"int "<<endl;add
return a+b+c;
}
int add(int a,int b,int c,int d)
{
cout<<"int "<<endl;
return a+b+c+d;
}
double add(double a,double b)
{
cout<<"double"<<endl;
return a+b;
}
int main(int argc,char* argv[])
{
//cout<<add(1,2)<<endl;
//cout<<add(1.1,2.2)<<endl;
if(argc==3)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
cout<<add(a,b)<<endl;
}
if(argc==4)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
int c=atoi(argv[3]);
cout<<add(a,b,c)<<endl;
}
if(argc==5)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
int c=atoi(argv[3]);
int d=atoi(argv[4]);
cout<<add(a,b,c,d)<<endl;
}
return 0;
}
6.缺省参数
1.定义: 缺省参数也叫默认参数,当调用函数不传入参数时,会自动填充参数
2.格式:返回值 函数名(类型 变量= 值,类型 变量 = 值){}
3.注意: 缺省可以做到部分缺省和全部缺省;
函数定义时缺省一定是从右往左缺省,不可以第一个参数缺省,第二个不缺省
只有自定义函数才能缺省,库函数没法缺省
传实参是从左向右缺省,但形参是从右向左缺省。
如果传入了实参,则形参的值就是实参的拷贝,如果没有传入参数,才会使用缺省参数。
实参个数必须大于或者等于无默认值的形参个数。不可以多于所有形参个数。
当使用缺省参数时,需要考虑函数重载的二义性。编译器不知道调用哪一个函数。
4.练习
int add(int a,int b= 0,int c= 0,int d = 0){ return a + b + c + d;}
5. extern "C" ”
使用: 在函数返回值前 加extern "c" 表示按照c语言的规则编译
格式:extern "C" void fun(int a);
extern "C" void fun(int a,int b);
注意: 加上后c语言规则中没有函数重载,不会修改函数名。
注意 "C" 为大写字母
加上extern “c”后,c++的函数和语法都正常只用,只是不修改函数名。
第二种定义方式: extern "c" {int fun(int x); int add(int x,int y);}
c++会默认定义 #define __cplusplus ,用来判断是c文件还是c++文件
案例:
extern "C" int add(int a, int b,int c){
cout << "a = " << a <<endl;
return a+b+c;
}
代码:
#include<bits/stdc++.h>
using namespace std;
int add(int a=0,int b=0,int c=0,int d=0)
{
return a+b+c+d;
}
int main(int argc,char * argv[])
{
//cout<<add()<<endl;
//cout<<add(1)<<endl;
//cout<<add(1,1)<<endl;
if(argc ==2)
{
int a=atoi(argv[1]);
cout<<add(a)<<endl;
}
if(argc ==3)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
cout<<add(a,b)<<endl;
}
if(argc ==4)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
int c=atoi(argv[3]);
cout<<add(a,b,c)<<endl;
}
if(argc ==5)
{
int a=atoi(argv[1]);
int b=atoi(argv[2]);
int c=atoi(argv[3]);
int d=atoi(argv[4]);
cout<<add(a,b,c,d)<<endl;
}
}
7、引用 (面试题:引用和指针的区别)
1.引用作用
引用时取别名,可以给变量取别名,避免使用临时变量出现。
2.定义
引用:数据类型 & 别名 = 原名;
指针定义: 数据类型 * 指针= &变量;
注意:引用自己没有内存空间。
如果说原名修改,引用的值也修改了。
引用不允许修改,只可以引用一次。
函数传参的方式:值传递,指针传递,引用传递。
案例:在函数中,使用引用,修改两个变量的值,形参实参都修改。
3.函数参数可以设置成引用
void fun(int& xx,int& yy)
3.函数的返回值为引用
int& fun(int xx);
注意:不可以返回局部变量的引用。
4.引用和指针的区别
第一个:引用的底层实现是指针(自学)
第二个:指针可以修改指向,而引用不可以修改
第三个:引用必须在初始化时进行赋值,而指针可以在使用时赋值
第四个: 没有空引用,引用必须连接到一块合法的内存空间
第五个:有指针的引用,没有引用的指针。int& *p = x是错误的。
第六个:引用的原名释放后操作引用就会错误,指针指向的内存空间释放,操作指针也会错误。
5.常引用
定义常量: const int x = 110;
定义常引用: conset int& x = y; x++;
常引用表示不可以通过引用修改值,但可以通过原名修改值。
常引用一般用于 函数的参数
代码:
#include<iostream>
using namespace std;
void ddd(int & a,int & b)
{
a=1;
b=1;
}
int main()
{
int a=2;
int b=2;
ddd(a,b);
cout<<"a="<<a<<endl<<"b="<<b<<endl;
}
8.new操作符(面试题:请讲new和malloc的区别)
1.new操作符的作用
c++利用new操作来开辟堆空间,和malloc相似。 也需要释放delete
2.匹配
new----delete
malloc---free
3.语法规则
格式1: 类型 * 指针变量 = new 类型标志符;
格式2: 类型 * 指针变量 = new 类型标志符(初始值);
格式3: 类型 * 指针变量 = new 类型标志符[内存单元个数];
代码:
#include<iostream>
using namespace std;
int main()
{
//用new创建普通变量
int* p = new int(10);
//用new创建一维数组
int* arr = new int[10];
//用new创建二维数组
int(*p1)[10] = new int[2][10];
//释放空间
delete p;
delete arr;
delete p1;
return 0;
}