目录
(1)如果一个函数里面经常要访问某个命名空间的成员,通过using关键词识别,这样操作这个成员的时候就不需要命名空间来访问了。
(2)在一个函数中如果已经对某个命名空间的成员通过using 标识,就不能再对其它同名的不同的命名空间的成员进行标识
(3)如果再一个代码中都要使用某一个命名空间中的成员,可以通过using标识整个命名空间,这样,这个命名空间中的所有成员都可以访问,一般放在最上面。
(1) 概念: c++提供了给变量取别名的机制,就是引用,引用时对c语言的一个扩充
(2)函数的参数的个数或类型或顺序不同(const int 与 int 也可以区分)
一、面向对象
ubuntu:安装g++编译器
命令:sudo apt-get install g++
1、C++发展
C++98标准 -----> C++03------>C++11------>C++14
2、为什么学C++?
应用领域: 应用软件开发 游戏开发 多媒体开发 人工智能
3、面向对象与面向过程
C语言:面向过程
(1)强调做算法
(2)大程序被分割成很多小程序,这些小程序被称为函数
(3)数据开放特点(封装性差)
C++:面向对象
特点:
(1)面向对象按照类来分隔组织程序,每个类都有特定的属性和方法,使得软件就像搭积木一样,更加容易组织
(2)维护代码的更少修改
4、面向对象语言的三要素
封装:把客观的事物封装成类,并且类中实现自己的数据和方法,对于不可信的进行信息隐藏。
继承:类和类之间的关系,省去了重复开发的时间
多态:同一个接口,不同的功能,也称为多种形态
二、C到C++过度
1、作用域限定符(::)
作用域限定符(域解析符):主要用于操作全局定义的变量或者类或者函数等等。
#include <iostream> //标准输入输出流
using namespace std;
int num = 100;
void test1()
{
printf("num = %d\n",num); //两种输出效果相同
cout<<"num = "<<num<<endl; //cout:输出函数 <<:输出运算符 ,链式输出,endl:换行
int num = 888;
//::作用域限定符(域解析符):主要用于操作全局定义的变量或者类或者函数等等
cout<<"num = "<<::num<<endl;
}
int main(int argc, char const *argv[])
{
test1();
return 0;
}
2、命名空间
目的:为了解决合作开发或者不同代码端之间的命令冲突问题,c++因此引入命名空间的概念
使用注意事项:
(1)如果一个函数里面经常要访问某个命名空间的成员,通过using关键词识别,这样操作这个成员的时候就不需要命名空间来访问了。
(2)在一个函数中如果已经对某个命名空间的成员通过using 标识,就不能再对其它同名的不同的命名空间的成员进行标识
void test2()
{
//如果一个函数里面经常要访问某个命名空间的成员,通过using关键词识别,这样操作这个成员的时候就不需要命名空间来访问了
using zhangsan::num;
cout<<"张三的num:"<<num<<endl;
num = 1000;
cout<<"张三的num:"<<num<<endl;
//在一个函数中如果已经对某个命名空间的成员通过using 标识,就不能再对其它同名的不同的命名空间的成员进行标识
//using Lisi::num;
//cout<<"lisi的num:"<<num<<endl;
using Lisi::myfun;
myfun();
}
(3)如果再一个代码中都要使用某一个命名空间中的成员,可以通过using标识整个命名空间,这样,这个命名空间中的所有成员都可以访问,一般放在最上面。
using namespace zhangsan;
void test3()
{
cout<<num<<endl;
myfun();
}
3、输入/输出函数(cout/cin)
输入,输出:cin,cout
#include <iostream> //头文件:输入输出流
using namespace std; //使用标准命名空间
void test1()
{
int a = 100;
printf("a = %c\n",a);
int ch = 'w';
printf("ch = %c\n",ch);
char b = 'w';
char c[] = "hello world";
float d = 3.141592685;
cout<<"a = "<<a<<endl;
//输出十六进制
//printf("a = %#x\n",a);
cout<<hex<<a<<endl;
//输出八进制
cout<<oct<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
cout<<"d = "<<d<<endl;
}
void test2()
{
//int a;
//cin>>a; //>>:输入运算符
cout<<dec;
//cout<<"a = "<<a<<endl;
int a,b,c;
cin>>a>>b>>c;
cout<<"a = "<<a<<" b = "<<b<<" c = "<<c;
cout<<endl;
}
int main(int argc, char const *argv[])
{
cout<<"hello world"<<endl; //cout:标准输出流对象 endl:换行
test1();
test2();
return 0;
}
4、register 关键字
作用:被register关键词声明的对象直接放在寄存器,大大提升了变量的访问速率
C与C++的不同点:
C语言中:register关键词修饰的变量不可以用&操作符取地址
c++中:可以对一个寄存器变量取地址,register关键词变为无效,会被强制放入内存中存储(成为普通变量)
5、struct 关键字
C与C++的不同点:
C语言中:内部不允许定义函数
C++中:可以定义函数;struct命名的结构体名字可以直接作为类使用;
//定义一个结构体
struct chinese
{
char name[32];
//c语言中内部不允许定义函数
//c++可以
void myfun()
{
printf("hello world!\n");
}
};
struct USA
{
char name[32];
};
//C语言代码
void IntroChinese(struct chinese *ch)
{
printf("%s是一个中国人\n",ch->name);
}
void IntroUSA(struct USA *ch)
{
printf("%s是一个外国人\n",ch->name);
}
int main(int argc, char const *argv[])
{
struct chinese ch = {"张三"};
struct USA u = {"BOB"};
IntroChinese(&ch);
IntroUSA(&u);
return 0;
}
//C++代码
void IntroChinese(chinese *ch)
{
printf("%s是一个中国人\n",ch->name);
}
void IntroUSA(USA *ch)
{
printf("%s是一个外国人\n",ch->name);
}
int main(int argc, char const *argv[])
{
chinese ch = {"张三"};
USA u = {"BOB"};
IntroChinese(&ch);
IntroUSA(&u);
return 0;
}
6、bool类型
true 为 1;false 为 0;(占一个字节)
#include <iostream>
using namespace std;
//c++支持bool类ing,可以赋值为true,或者false,占一个字节
int main(int argc, char const *argv[])
{
bool a = true;
cout<<"a = "<<a<<endl;
bool b = false;
cout<<"b = "<<b<<endl;
a = -0.00000001;
cout<<"a = "<<a<<endl;
cout<<"sizeof(bool) = "<<sizeof(a)<<endl;
return 0;
}
7、三目运算符
C与C++的不同点:
C语言:三目运算符返回的是一个常量
C++:返回的是一个变量
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a = 1,b = 2;
int num = (a > b)?a:b;
(a > b)?a:b = 100; //C语言中,返回的是一个数值,c++中,返回的是一个变量
return 0;
}
8、const关键字
C与C++不同点:
C语言:const修饰的是只读变量,但是可以通过地址来修改其值。
C++:是一个真正的常量,不可以通过地址或者变量来修改其值,因为其存放在符号表中,所以也就是说,不能对其取地址;但是当对const修饰的变量取地址的话, 系统会为其分配一定内存空间,并且用常量来填充。
图中 a 的值是不变的,也就是说,C++中 不可修改。
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
const int a = 1;
//a++;
int *p = (int *)&a;
//对const修饰的常量取地址,编译器会分配一个整形的长度,并且把数字1填写到对应的内存中
*p = 2;
cout<<"a = "<<a<<endl;
cout<<"*p = "<<*p<<endl;
return 0;
}
9、C++引用
(1) 概念: c++提供了给变量取别名的机制,就是引用,引用时对c语言的一个扩充
《注意》:typedef:是给数据类型取别名,不能对变量进行重命名。
下面是通过引用实现,两个数的互换:
int &c = a; //引用一定要初始化
//int &d = 100; //不能用常量初始化引用
#include <iostream>
using namespace std;
void Swap(int &x,int &y)
{
int tmp = x;
x = y;
y = tmp;
}
int main(int argc, char const *argv[])
{
int a = 100,b = 200;
cout<<"交换前:"<<"a = "<<a<<" b = "<<b<<endl;
Swap(a,b);
cout<<"交换后:"<<"a = "<<a<<" b = "<<b<<endl;
int &c = a; //引用一定要初始化
c = 1000;
cout<<"a = "<<a<<endl;
//int &d = 100; //不能用常量初始化引用
return 0;
}
(2)引用的本质:常指针
当分析复杂语法现象的时候,当作常指针来分析,分析一般语法,当别名分析
struct test
{
int &a; //其相当于一个常指针,大小为8个字节,两个为16个字节
char &c;
};
int main(int argc, char const *argv[])
{
int a = 1;
char c = 'c';
int &pa =a;
char &pc = c;
//int &pb = c; //左右类型要一致
cout<<"sizeof(test) = "<<sizeof(test)<<endl;
//当分析复杂语法现象的时候,当作常指针来分析,分析一般语法,当别名分析
cout<<"sizeof(pa) = "<<sizeof(pa)<<endl;
cout<<"sizeof(pc) = "<<sizeof(pc)<<endl;
return 0;
}
(3)引用作为函数的返回值
注意:引用作为函数的返回值时,不能返回局部数据(局部变量,局部对象,局部数组等)的引用,因为当函数调用完成后,局部数据都会被销毁,数据不存在了。可以返回一个全局变量或者静态变量的引用。
将引用作为函数返回值的函数,有4中处理方式:
1> 不接收函数返回值
2> 用一个普通变量接收函数返回值,这个时候接收的是变量的值而不是变量的引用
3> 用一个引用接收函数返回值,接收的就是一个引用
4> 当成左值使用
#include <iostream>
using namespace std;
int g = 100;
int& f1()
{
int x = 1;
return g;
}
int main(int argc, char const *argv[])
{
//用法1:不接受函数返回值
f1();
//用法2:用一个普通变量去接收函数的返回值,返回的是g的值
int a = f1();
a = 1000;
cout<<"a = "<<a<<endl;
cout<<"g = "<<g<<endl;
//用法3:用一个引用去接收函数的返回值,接收的就是一个引用
int &b = f1();
b = 1000;
cout<<"b = "<<b<<endl;
cout<<"g = "<<g<<endl;
//用法4:当成左值使用
f1() = 200; //g = 200;
cout<<"g = "<<g<<endl;
return 0;
}
(4)指针引用(给指针取别名)
用指针引用代替二级指针:
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef struct student{
int id;
char name[32];
}ST;
void ceate_student(ST* &stu) //取代了二级指针
{
stu = (ST *)malloc(sizeof(ST));
if(stu == NULL)
{
cout<<"malloc error"<<endl;
exit(-1);
}
stu->id = 100;
strcpy(stu->name,"bxp");
}
void printf_student(ST *stu)
{
cout<<"id = "<<stu->id<<" name = "<<stu->name<<endl;
}
int main(int argc, char *argv[])
{
ST *stu = NULL;
ceate_student(stu); //无需取地址
printf_student(stu);
return 0;
}
(5)常引用
常引用:指不能通过引用来改变引用对象的值
使用方法:
1>使用普通变量初始化常引用
int a;
const int &b = a; //b是a的常引用,a和b代表同一块内存空间,但是不能通过b修改a的值
2>使用常量初始化常引用(不可以用常量初始化普通引用)
const int &num = 10;
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a =1;
const int &b = a;
//b = 2; //不能通过常引用修改其值
const int &pb = 100; //可以用常量初始化常引用
//int &pd = 100; //不可以用常量初始化普通引用
int *p = (int *)&pb;
(*p)++;
//pb++;
cout<<"pb = "<<pb<<endl;
return 0;
}
10、内联函数
内联函数:在编译时将函数调用处直接用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数叫做内联函数(内嵌函数/内置函数)
内连函数创建方法:只需要在函数定义处增加关键字inline。
#include <iostream>
using namespace std;
//只需要在函数定义处加关键词inline即可
inline int MyMax(int a,int b)
{
return (a > b) ? a: b;
}
#define MAX(a,b) (a) > (b) ? (a):(b)
int main(int argc, char const *argv[])
{
int a = 1,b = 2;
cout<<MyMax(1,2)<<endl;
int ret = MAX(++a,b);
cout<<"ret ="<<ret<<endl;
return 0;
}
注意事项:
1>.不能存在任何形式的循环语句
2>.不能存在过多的条件判断语句
3>.函数体不能过于庞大
4>.不能对函数进行取地址操作
5>.函数内联声明必须在函数调用之前
总结:内联函数比普通函数省去了函数调用时压栈,跳转,和返回等开销,因此,当函数体的开销远大于压栈,出栈等开销时,内联函数会变得没有意义。
11、C++函数中默认参数
c++中可以给形参一个默认的值,当我们在使用函数时,如果不传参,则使用这个默认值。
使用方法:
默认参数:将一个值设置为默认参数,那么右边所有的参数都必须设置默认值
如果给默认参数传参,则使用传的参数,不使用默认值
#include <iostream>
using namespace std;
//默认参数:将一个值设置为默认参数,那么右边所有的参数都必须设置默认值
//如果给默认参数传参,则使用传的参数,不使用默认值
void Add(int x,int y = 0,int z = 1) //设置y的默认值为1,int y = 1被称为默认参数
{
cout<<"x + y = "<<x + y<<endl;
}
int main(int argc, char const *argv[])
{
Add(1);
return 0;
}
12、C++函数中占位参数(一般与默认参数一起使用)
占位参数没有初始值时,函数调用时需要传参。
void Add(int a,int b,int = 0) //一般和默认参数一起使用
{
cout<<a+b<<endl;
}
int main(int argc, char const *argv[])
{
Add(1,2);
cout<<sizeof(A)<<endl;
return 0;
}
13、C++函数重载
三个条件:
(1)函数名相同
(2)函数的参数的个数或类型或顺序不同(const int 与 int 也可以区分)
(3)和函数的返回值类型无关
#include <iostream>
using namespace std;
void Swap(int &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
/*int Swap(int &a,int &b) //和返回值类型无关
{
int tmp = a;
a = b;
b = tmp;
return 1;
}*/
void Swap(int &a,double &b) //参数的类型不同
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(int &a,int &b,int &c) //参数的个数不同
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(double &b,int &a) //参数的顺序不同
{
int tmp = b;
b = a;
a = tmp;
}
int main(int argc, char const *argv[])
{
int a =100,b = 200,c;
Swap(a,b);
cout<<"a = "<<a<<" b = "<<b<<endl;
double d = 3.14;
Swap(a,d);
Swap(a,b,c);
Swap(d,a);
return 0;
}
函数重载的二义性:以下代码会产生二义性
14、C++的动态内存分配
初试new 与 delete:
C语言: 动态内存分配使用malloc函数,释放使用free函数。
C++中:malloc和free函数仍然可以使用,但是我们更多会使用new和delete,为c++类和对象设计
C与C++的不同:
(1)new/delete是关键词,malloc/free是函数
(2)malloc和free的返回值是void*类型,new/delete返回值类型为申请对象的指针类型
(3)malloc申请空间的时候不能初始化,new可以初始化
(4)malloc不能自动调用类的构造函数,free不会自动调用析构函数,new和delete可以。
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int *p = new int; //分配了1个int型的内存空间,返回值类型为int*类型
*p = 100;
cout<<"*p = "<<*p<<endl;
delete p; //释放p指向的内存空间
p = NULL;
int *q = new int(200); //申请对象空间的同时,并且对申请的空间初始化为200
cout<<"*q = "<<*q<<endl;
delete q;
q = NULL;
int *q2 = new int[5]{1,2,3,4,5}; //c++11标准,c++11前不可以初始化动态数组
/*for(int i = 0; i < 5;i++)
{
q2[i] = i;
}*/
for(int i = 0; i < 5;i++)
{
cout<<q2[i]<<" ";
}
cout<<endl;
delete []q2; //释放一个数组
q2 = NULL;
return 0;
}
多维数组的创建和释放:
例:二维数组的动态创建,例如申请存放二维数组 int a[5][6]的空间
例:三维数组的动态创建,例如申请存放二维数组 int a[5][6][7]的空间;