可移植性要考虑硬件(不同的芯片)和软件(不同的操作系统)
OOP:面向对象设计
c++支持的编程流派
1 C语言的面向过程
2 OOP面向对象设计
3 模板和泛型编程
编写c++需要的几个套路
include 标准输入输出流,相当于c语言的stdio
using namespace std;//使用标准命名空间,命名空间可以简单理解成一个房间
c++输出流的几个问题
1 如果想要换行需要在后面追加
命名空间的几个问题
命名空间里面可以存放的东西
变量 函数 结构体 类。。。
命名空间是为了解决不同代码下函数名或其他成员重名的问题,这样大大提高了可移性
命名空间 必须声明在全局作用域下,不可以命名到局部作用域下
命名空间可以嵌套命名空间
namespace B
{
int num=10;
namespace A
{
int num=20;
}
}
可以直接用B::num访问B空间下的num,用B::A::num访问A空间下的num
命名空间是开放的,可以随时给命名空间添加新的信息
namespace B
{
int a=10;
}
namespace B
{
int b=20;
}
//此时命名空间是同时含有a和b的,可以随时往里面添加新成员
命名空间可以是匿名的
namespace
{
int c=10;
int d=30;
}
//本例中没有给命名空间命名,就是命名,相当于在全局中声明,相当于
//static int c=10;static int d=30;
命名空间可以起别名
namespace veryLong
{
int e=40;
}
void test()
{
namespace else = veryLong;//这样就给veryLong命名空间起了别名,用els来代
cout <<veryLong::e<<endl;
cout <<else::e<<endl;
//上述两行代码效果医院
}
using声明以及using编译指令
就近原则和using声明同时出现就会出错,尽量避免,但是using编译指令与就近原则
同时出现优先使用就近,当没有就近原则的时候,同时使用多个using编译指令需要加作用域区分
C++对C语言的增强和拓展
1 全局变量检测增强
int a;
int a=10;
上述代码在C语言中可以编译通过,但是C++不行
2 函数检测增强
get(w,h)
{
return w*h;
}
void test()
{
printf("%d\n",get(10,10,10));
}
上述代码在C语言中是可以编译通过,但是C++不行。说明C语言的返回值没有检测,函数调用参数个数没有检测
3 类型转换检测增强
void test()
{
char *p=malloc(64);
//malloc的返回值是void*,但是上述代码左边是char *
}
上述代码在C语言里是可以编译通过的,但是在C++里是不行的必须得写成下面这样才行
void test()
{
char *p=(char *)malloc(64);//加入强制转换类型
}
4 struct增强
struct Persion
{
int age;
void func();//C语言下结构体中不能有函数
}
void test()
{
struct Persion p;//C语言中创建结构体变量必须加struct关键字
p.age=100;
}
C++中的结构体可以放函数,而且可以不加struct关键字
5 bool类型的扩展
C语言下没有这个数据类型,该数据类型代表真(1)和假(0)
将非零的数都转换为 1
bool类型只占一个字节的空间
6 三目运算符增强
void test()
{
int a=10;
int b=20;
printf("%d"a>b?a:b);
a>b?a:b;//在C语言中是不允许这行代码的存在的但是C++可以,而且最后b=100
//这是因为在C语言中三目运算符返回的是一个值,而c++返回的是一个变量
}
const增强
全局const
```c
const int a=100;
void test()
{
//a=10;//这样直接改值会报错,直接修改不行
//下面通过间接修改的方式修改,这种方式在C语言里是可以通过编译的
//虽然没有语法错误,但是执行生成的可执行文件会报错,
//因为定义全局变量之后,受到常量区的保护,运行修改失败
int *p=&a;
*p=20;
}
```
局部const
void test()
{
const int b=100;
//b=200;//直接这么修改依旧会报错,但是用下面的间接修改的
//方式是可以修改成功的
int *p=&b;
*p= 20 ;//因为此时的全局变量分配到栈区上,相当于在内存上的
}
int arr[a];在C语言下,const是伪常量,是不能用来初始化数组的
在C++下,全局const的结论和C语言的结论一样,但是C++下局部const的间接修改
的方式虽然编译通过了,而且能运行可执行文件,但是运行的结果不会修改值,是修改
失败的,而且int arr[a];是可以这么对数组初始化的,所以C++下面const修饰的是一个真正的常量
原理大概描述
C++能做到上述操作的原因是把const修饰的放到了符号表里 ,符号表里是用键值对的
形式,一个常量对应一个值,只要你引用常量就会去访问符号表的键值对。
int *p=(int *)&b;在C++里能执行但没效果的原因是,这条代码对C++相当于
int temp =b;
int *p=&temp;最终他指向的是temp这个自动生成的中间变量。
当对const修饰的局部变量取地址的时候,编译器给变量分配临时内存空间temp(在栈区上)
,p指针指向的是temp
在C语言中const修饰的变量是一个外部链接属性的,在c++中默认是内部链接属性
(该变量可以在本文件使用,但是在外部文件就不能用了),除非加入extern关键字
使他变为外部链接属性
const分配内存的情况
1 对于const变量取地址会分配临时内存
2 使用普通变量来初始化const变量,比如下面这种
```c++
void test()
{
int a=10;
const int b=a;
int *p=(int *)&b;
*p=1000;//这种情况下在c++里是可以修改成功的(此时分配到内存里)
//把a换成10,那么这样是不能修改成功的
}
```
3 对于自定义数据类型,也会分配到内存里
```c++
struct persion
{
string name;//c++里一个字符串类,如果想用这个需要包含头文件include<string>
int age;
}
void test()
{
const persion p;
//p.age=10;//这种直接修改依旧会报错
persion *pp=(persion *)&p;//这种间接修改的方式就可以实现修改
(*pp).name="tom";
pp->age=10;
}
```
用常量初始化就绝不会被修改
在C++里尽量用const替换#define
引用
int &b=a;
表示对a的引用,引用的本质是起别名
引用的基本语法 类型 &别名=原名
引用必须初始化,光写int &b;会报错
引用一旦初始化后,就不可以指向其他变量
对数组建立引用
1 直接建立引用
int arr[10];
int (&p)[10]=arr;//这样编写即可直接引用
2 先定义出数组类型,再通过类型定义引用
typedef int(p)[10];//表示用p 代表一个长度为10的整型数组
p &p2=arr;
可以为一个变量建立多个引用,起多个别名
用引用的方式把变量传入函数,可以更改变量的值
引用的注意事项
1 引用必须引一块合法的内存空间
int &a=10;//这么写是不行的
2 不要返回局部变量的引用
函数的返回类型可以是引用
int& func()
{
int a=0;
return a;
}
void test()
{
int &ref=func();
count << "ref"<<ref<<endl;
count <<"ref<<ref<<endl;"
}//上述代码的现象是第一次引用是10,第二次释放局部变量的内存之后就是随机值了
当函数返回值是引用,那么函数的调用可以作为左值,比如
fun2()=1000;
3 常量的引用
void test()
{
//int &ref=10;//上文提到这么写是会直接报错,但是下面这样写不会报错
const int &ref=10;//加了const之后,相当于写成int temp=10;const int &ref = temp;
//并且可以通过如下方式来对10进行修改
int *p=(int *)&ref;//(int *)是进行一个强制类型转换
*p=10000;
//这样ref就被改成了10000
}
常量引用的使用场景 const修饰函数形参防止误操作
引用的本质在C++内部实现是一个指针常量,引用所占的空间大小与指针相同
利用引用可以简化指针,可以直接用同级指针的 引用,给同级指针分配空间
函数重载的实现原理
由编译器自己给你改成别的名字,不同的编译器改的名字不同,这地方咱们普通用户
就不用操心了
C++调用C语言函数
C++中的函数重载会对函数名做修饰,所以调用C语言函数会发生链接错误需要下面的方式处理
extern c
如果C++和C语言混合编程,在c++里想调用C语言代码下的一个函数,你需要加入
extern "C" void test() 这样来告诉编译器用C语言的方式去链接这个函数,同时这样写,就不需要
include "test.h"(声明test的头文件了)
另一种方式
但是上述书写方式如果需要调用的函数太多就很麻烦,一般不那样写
我们一般在C语言的头文件test.h开头加入
#ifdef __cplusplus
extern "C" {
#endif
在test.h文件末尾加入
#ifdef __cplusplus
}
#endif
然后在C++源码中包含include "test.h"就可以了
类和对象的基本概念
面向对象的三大特性,封装 继承 多态,C语言下虽然也有封装但是缺点是属性 和 方法是分离的
导致别的东西也可以调用你的方法,造成混乱
C++封装
理念:将属性和行为(成员方法)作为一个整体来表现生活中的事物
将属性和行为加以权限控制,权限分为3种
public 公共权限
成员在类内 类外都可以访问
private 私有权限
成员在类内可以访问 类外不行
protected 保护权限
成员在类内可以访问 类外不行
该权限和继承有关,子类可以继承来访问父类的东西
class和struct的区别是class的权限是默认是私有的,struct默认是公共的
尽量将成员属性设置为私有,这样自己可以控制读写权限,可以对设置的内容加一个有效性验证
char *可以隐式类型转换为string