【系统开发基础储备】C/C++语言语法(第一篇)

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
TODO:写完再整理

文章目录

  • 系列文章目录
  • 前言
  • 一、C++在C基础上的改进
    • 1.C语言和C++语言的关系
    • 2.C++的开发工具
    • 3.面向对象的思想
    • 4.面向过程和面向对象的两种思维比喻
    • 5.面向对象思想的的特点
    • 6.C/C++的特点
      • (1)C++特点:
      • (2)使用面向对象的编程技术开发程序的基本步骤:
      • (3)面向对象的优点
      • (4)高级的面向对象编程方法
      • (5)解决程序的阻塞性
  • 二、C++自带的的数据结构
    • 1.布尔型bool
    • 2.整型int(int_16、int_32、uint_16、uint_32...)
    • 3.浮点型float/double
    • 4.字符型char
    • 5.字符串型string
    • 6.数组array
    • 7.向量vector(补充)
    • 8.指针pointer(引用也行)
      • 0、科普:
      • 1、定义
      • 2、背景
      • 3、功能
      • 4、变量寻址方法:
      • 5、指针变量声明(定义)的方法
      • 6、注意:
      • 7、利用指针改变值的方法:
      • 8、区别星号的用途
      • 9、指针和数组的关系
      • 10、用指针访问同一数组的不同元素方法
      • 11、指针和函数调用的关系
      • 12、指针和结构体的关系
      • 13、this指针
      • 14、数组和指针的关系:
      • 15、指针函数
    • 9.结构体struct
      • 1、背景
      • 2、结构使用
    • 10.类class和对象
      • 0、使用类的一个原则
      • 1、类和结构体的关系
      • 2、类和对象的关系
    • 11.联合union
      • 1、联合定义
      • 2、联合定义语法:
      • 3、创建联合类型变量语法:
      • 4、联合类型赋值语法:
    • 12.枚举eunm
      • 1、功能
      • 2、注意
      • (1)创建枚举类型:
      • (2)创建枚举变量
      • (3)枚举变量赋值
    • 13.类型别名、const和define
      • 1.const和define的区别
      • 2.类型别名typedef
  • 三、C++的模块结构【重要】
    • 1.C/C++操作符
      • (1)取地址运算符“&”--用于取变量的地址
      • (2)成员运算符“.”
      • (3)“<<”“>>”操作符
      • (4)作用域运算符"::"
      • (5)条件运算符"?:"
    • 2.调试及显示的输入输出流
      • (1)流的概念
      • (2)print和cout输出流(scan/cin输入流)的区别
      • (3)输出流对象常用的功能函数
      • (4)输出流对象常用的用法
    • 3.文本读写权限操作及库解释
      • (1)标准库
      • (2)传入参数argc\argv[]
      • (3)文本操作
    • 4.传值、传址、传引用
      • (1)传值(普通变量的值)
      • (2)传址(指针变量的地址)
      • (3)引用传递(我常用)
      • (4)注意:
    • 5.强制类型转换
      • 1、方法
      • 2、功能
      • 3、例子:
      • 4、数据类型的运算和强制转换错误
    • 6.重载机制及多态性
      • (1)函数重载定义
      • (2)不同的数据类型重载函数实现方法:
      • (3)不同的参数个数的重载函数实现方法:
      • (4)好处:
      • (5)(类)重载机制
      • (6)(运算符)重载机制
      • (7)重载"<<"操作符
      • (8)多态性
    • 7.全局变量和静态方法static,虚函数和纯虚函数virsual
      • 静态方法:
        • 1、适用场景
        • 2、静态方法的使用
        • 3、静态方法的调用语法
        • 4、静态方法的注意
        • 5、优点
      • 虚方法(virsual method)
        • 1、功能
        • 2、使用场景
        • 3、注意
        • 4、虚方法的用法
        • 5、优点
        • 6、经验
    • 8.动态内存管理
      • 静态内存
        • 1、定义
        • 2、静态内存的弊端
      • 动态内存(对于基本类型和对象)
        • 1、使用场景
        • 2、功能
        • 3、定义
        • 4、注意
        • new和delete
      • 动态数组
        • 1、功能
      • 避免内存泄露
    • 9.命名空间和模块化编程
      • (1)命名空间namespace
        • 1、使用背景
        • 2、功能
        • 3、方法
        • 4、注意
      • (2)模块化编程(工厂设计的方法基础):
        • 1、使用背景
        • 2、头文件:后缀名为.h文件
        • 3、自定义头文件功能
        • 4、注意
    • 10.模板template语法
    • 11.经验
      • 1、主函数都要有return
      • 2、合法性检查
      • 3、发布出去的程序都要做压力测试
      • 4、程序越简化越好
      • 5、for语句可以临时定义一个i
      • 6、要用的变量最好先初始化一遍,避免随机初始化
      • 7、强制转换时在该变量前加一个(数据类型),如(float)a
      • 8、设计程序要考虑通用性(以后可以偷懒)、预错性
  • 四、C++工具及STL库(刷题的时候常用)
    • 1.STL库
    • 2.矩阵运算库eigen3
    • 3.LCM轻量级通讯库
    • 4.......
  • 面试相关的概念
    • C++语言与数据结构、算法的关系
    • c语言和c++有什么区别
    • C++的继承性体现【公有继承、受保护继承、私有继承的区别】
    • C++的多态性体现
    • 类模板、函数模板的概念
    • C++空类默认有哪些成员函数
    • C++中类与结构体的区别
    • C++中结构体和联合体的区别
    • 纯虚函数、虚函数的作用
    • 内联函数和普通函数的区别
    • 析构函数的作用(避免内存泄露)
    • 重载与重写的区别
    • 常用的设计模式
    • 智能指针是什么?智能指针怎么实现?什么时候改变引用计数?
    • 数组指针和指针数组的区别
    • 指针常量和常量指针
    • 指针和引用的区别
    • C++函数中值的传递方式有哪几种?
    • 如何实现类对象只能静态分配或动态分配?
    • 避免内存泄露的方法【C++的内存管理】
    • 关键字new与malloc的区别
    • 关键字extern的作用
    • 关键字static的作用
    • 关键字define的作用
    • 关键字const的作用
    • 关键字register的作用
    • 关键字volatile的作用
    • 关键字typedef的作用
    • 头文件中的ifndef/define/endif 是干什么用的
    • Makefile文件的作用
    • main 函数执行以前,还会执行什么代码?
    • 原子操作的概念【有点汇编语言指令的味道】
    • 线程和进程的联系和区别
    • 线程有哪几种状态
    • 进程间的通信方式
    • 线程同步和线程互斥的区别
    • TCP和UDP有什么区别
    • stl库提供什么样的容器(数据结构)?
    • vector和队列的区别是什么?
    • 优先级队列有什么用?
    • 堆和栈的区别
    • 自动数据类型auto
    • 关于sizeof的认识
    • 使用过的 shell 命令
    • 使用过的 vim 命令
  • 参考资料


前言

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!

本文先对C/C++语言语法做个简单的介绍,具体内容后续再更【防盗标记–盒子君hzj】,其他模块可以参考去我其他文章


提示:以下是本篇文章正文内容

一、C++在C基础上的改进

1.C语言和C++语言的关系

1、C语言已经有模块化和结构化的优势,但是还是一个面向过程的语言
2、C++语言增加了面对对象的机制,同时支持面向过程
3、C++对C语言的扩充
(1)C++变量的定义可以在程序中的任意一行(这样在大型程序中,变量灵活定义能大大提高可读性,但是C语言用声明也能解决这个问题)
(2)提供了标准的输入输出对象,cin\cout
(3)**用const代替了define做宏定义**
(4)提供函数重载、函数模板、带默认值的函数
【防盗标记--盒子君hzj】
(5)**引用类型**
(6)单目作用域运算符
(7)string类型字符串
(8)使用了new和delete代替了malloc和free函数
(9)从C语言的面向过程的编程方式,过度到面向对象的的编程方式。这样更有效的管理复杂,庞大的代码
(10)C++能开发,编译器、操作系统、应用软件、游戏等等。

.

2.C++的开发工具

1、记事本(notepad++)+命令行(上手慢,大牛级别)
2、visual C++6.0(太古老,和现在流行的系统会有冲突)
3、VS2015(功能强大,安装包和一样强大)
【防盗标记--盒子君hzj】
4、code::block(比较好的C++开发工具,适合专业人员)
5、集成IDE:DEV C++(太老了)、CLion(非常好,收费)、CFree(国产),XCode(适合苹果系统)等等
我当然使用的是廉价的vscode啦~

.

3.面向对象的思想

把一个复杂的对象,不断细分成一个子对象,逐一突破,每个对象由属性和行为两个要素
面对对象的思维转变:程序员不在面对一个个函数和变量,而是要放眼大局,**面对一个个对象看待问题**

.

4.面向过程和面向对象的两种思维比喻

面向过程类似于企业老总什么都要自己亲力亲为,累得要死
面向对象类似于企业老总吧公司分成几个板块,任命经理对象,由经理对象处理好各自板块的问题,我仅仅需要管理好经理即可。

.

5.面向对象思想的的特点

1、封装(类似于分公司):把对象的属性和方法结合成一个独立的系统单位,并尽可能的隐藏对象的内部细节(包括复杂的函数实现和变量定义),这样能把程序变得更加“仔细”,更加“模块化”
2、抽象(类似于一个总公司):相当于总公司要对分公司下达的一些指令和指标。如同一个协议吧
3、继承:类似于儿子继承了老爸(基类,父类)的所有属性,并在这个基础上儿子(子类)有所扩展(属性和方法)
4、多态:和继承相关,就是儿子对爸爸有所扩展的部分,同时能继承多个基类

在团队开发中,这些特点更有利于分工合作~
.

6.C/C++的特点

(1)C++特点:

1、没有数组溢出大小检查
2、C++面向对象的编程一般程序比较长,因为要对每个对象进项详细的描述,但是这样的好处是主函数特别精简,可读性非常高

.

(2)使用面向对象的编程技术开发程序的基本步骤:

1、定义一个有属性(变量)和方法(函数)的类(模板)	
2、实现方法的过程(构造函数)
【防盗标记--盒子君hzj】
3、调用方法实现对象的功能

.

(3)面向对象的优点

1、面向过程编程偏向于关注对数据的处理过程,面向对象的编程是偏向于对数据进行怎行的处理,两者有很多相通的地方。

2、面向对象的编程方法的一个重要特征是用一个对象把数据和处理数据的函数封装到一起。越高级的语言封装的越多,每个函数只处理调用它的那个对象,所包含的数据,所有的数据偶属于同一个对象,类仅仅是一个描述对象的模板

3、面向对象是一个国家分成每个家庭进行管理,一出错仅仅某个家庭受害;面向过程是一个国家一起管理,一出错大家一起受伤害

(4)高级的面向对象编程方法

静态成员,静态对象、静态方法、虚方法、抽象方法、多态

.

(5)解决程序的阻塞性

意思是程序在不进行动作的时候一直等待,一直占用资源部释放
相反的,还有非阻塞编程,**多进程多线程编程**

.
.

二、C++自带的的数据结构

1.布尔型bool

布尔型bool不是true就是false

2.整型int(int_16、int_32、uint_16、uint_32…)

定义变量
1、用数据结构定义变量,如int a\float a \double a\char a
2、用类定义变量,如,类名 a;[app a;]
【防盗标记--盒子君hzj】

3.浮点型float/double


4.字符型char


5.字符串型string


6.数组array

**1、功能**:可以把许多同类型的值存储在同一变量名下
数据类型声明:数组仍然要被声明为某一特定的类型:int \float\double\char等等
**2、定义方法**:type name[x]
**3、注意**:不同类型的值不能放在同一数组上
**4、字符串储存类型**:在C语言中,字符串其实是储存在一个字符数组里的;在C++语言中,不必这么做了,C++提供了std::string这个类
getline(std::cin>>str),直接输入一行字符串存储在str中
【防盗标记--盒子君hzj】
**5、实质**:计算机是把数组以一组连续的内存块保存的,如:int array[3]={1,2,3};
这说明数组是拥有很多个地址的,而且每个地址都对应这一个元素,同一数组拥有一样的变量名(都是array)

7.向量vector(补充)


8.指针pointer(引用也行)

0、科普:

(1)程序是在内存里面存储的,但是它们是在内存里面运行的,所以地址是特指内存里面的地址
(2)变量的地址在程序的运行过程中是不会被改变的,但是变量在程序不同时间段上运行时会改变的,因为程序运行完成后会释放内存和变量

1、定义

指针是专用来存放地址的特殊类型的变量

2、背景

绝大部分的高级或多或少都会使用了指针,但是就是被包装了起来

3、功能

指针能完成很多其他工具没有完成的任务,如对内存的调用
【防盗标记--盒子君hzj】

4、变量寻址方法:

对于一个变量,我们有两种方法对它进行寻址
方法一:通过变量名
方法二:通过地址,需要“取址”操作符--“&”,它的作用是获得变量的地址
“&”d的使用方法:
	--int var=123;
	--std::cout<<"var的地址:"<<&var

5、指针变量声明(定义)的方法

--type*pointername;【*代表指针变量】,如
		方法一:
			--int *p;【定义一个指针变量p】
			--int pp=123;【定义一个整形变量pp】
			--p=&pp【把整形变量pp的地址赋给指针变量p里】
		方法二:
			--int pp=123;
			--int*p=&pp;【一步到位】

6、注意:

(1)整型数据结构的变量要用整型数据结构的指针指向,做到意义对应,因为内存对齐问题
(2)int *p1 p2 p3【这样定义仅有p1是指针变量,p2 p3都是整形变量,这样写的程序是具有极大迷惑力的,一般不同类型的变量分开写】
【防盗标记--盒子君hzj】

7、利用指针改变值的方法:

(1)原理:指针变量可以让我们知道变量的地址,这样我们就可以通过指针访问该地址的数据(走后门)
(2)方法:解引用处理:即在指针变量前加上*【可以这么理解加*往上层走,加&往下层走】
		方法一:
			--int a=100;
			--int*aa=&a;
			--std::cout<<*aa;【输出的是100】
		方法二:
			--int a=100;
			--std::cout<

8、区别星号的用途

(1)--int*aa=&a;【这种形式是指针的定义,定义是带数据结构的】
(2)--*aa=1000;【这种形式是指针的解引用,引用不带数据结构的】

9、指针和数组的关系

背景:计算机是把数组以一组连续的内存块保存的,如:int array[3]={1,2,3};
这说明数组是拥有很多个地址的,而且每个地址都对应这一个元素,同一数组拥有一样的变量名(都是array)
【防盗标记--盒子君hzj】
实际上,数组的名字就是一个指针(变量的名字也是指针),指向数组的基地址(第一个元素),故下面两句本质是一样的
--int*ptr1=&array[0];
--int*ptr2=&array;

10、用指针访问同一数组的不同元素方法

(1)方法:ptr++;
(2)注意:这里的指针++不是地址位置简单的++,而是以数据结构对应的地址数目++,因为不同的数据结构的地址数目是不一样的
(3)一般用法:
		--int array[10]={1,2,3,4,5,6,7,8,9,10};		【定义一个数组】
		--int *array=&array							【定义一个指针,指向该数组的首地址】
		--std::cout<<*array;							【输出数组的第一个元素】
		--*array++;
		--std::cout<<*array;							【输出数组的第二个元素】
			.........
注意*array+1和*(array+1)的区别:优先级问题

11、指针和函数调用的关系

		--int a=100;
		--int b=1000;
		//子函数
		void add(int *one,int *two)
		{
			int sum;
			sum=*one+*two;
			std::cout<

12、指针和结构体的关系

背景:指针也可以指向结构体,方法和指向其他任何变量一样(类似于数组)
步骤:
第一步:
(1)定义结构体:
struct name
{
	type1 varname1;
	type2 varname2;
	.....
};
第二步:
(2)赋值语法
name hzj={1,2};
【防盗标记--盒子君hzj】
第三步:
(3)创建指向该结构变量的指针
name *pzhj=&hzj;
注意:指针的类型必须和结构体变量的类型是一样的,都是name

结构体变量指针的调用
方法一:返回层次操作:通过"."解引用符
(*pzhj).varname1=100;			【这里改变了hzj这个结构体内的varname1成员的值】
*pzhj本质上和hzj一样,都是结构体变量;pzhj是hzj的的基地址,因为hzj结构体变量的成员数据结构不一样,不可以使用像数组变量"++"的形式

方法二:指针层面操作:通过"->"解引用符
phzj->varname1=100;		【这里是直接操作phzj指针】

13、this指针

使用this指针的原则:如果**代码不存在二义性隐患**,就不必使用this指针
this指针是类的自动生成、自动隐藏的 私有成员,存在于类的非静态成员函数中,指向被调用函数对象的所在地址
this指针是当前指针地址的意思
【防盗标记--盒子君hzj】

14、数组和指针的关系:

数组的数组名和下标操作符[]可以对应为指针的基地址指针和对应的指针运算++
int a[20];
int *x=a;
指针变量x指向a的首地址即a[0]的地址,a[0]和*x都代表数组的第一个元素 ,根据数组和下标操作和指针的指针运算,a[1]等价于*(x+1)......a(20)等价于*(x+20)

15、指针函数

1、功能:动态内存可以让函数返回一个地址,以前函数一般都是仅能返回一个标量值(整型浮点型指针等等)
基本思路:

2、使用方法:函数返回一个地址(该函数是指针函数,如,int *funtion(int a);)
在函数里调用new语句为某个对象或者某个基本数据类型分配一块内存,
再把该块内存的地址返回给主程序的代码,主程序的代码使用完这个地址后使用delete对该块内存进行释放

3、注意:任何一个指针函数都不应该把函数内部的指针(局部变量的指针)作为返回值,
因为当函数执行完毕后,局部变量自动被清空,返回的地址是一个乱码。
返回的地址应该是用new动态分配的内存基地址
【防盗标记--盒子君hzj】

9.结构体struct

结构体structure(本质是面向对象,对象的基础)

1、背景

C和C++的程序完全可以根据具体情况自定义一些新的数据类型,
并创建新的数据类型变量,这个为对象的创建打下了基础

2、结构使用

是一种有程序员定义的,由多种变量类型组合而成的数据类型【组合】
**(1)定义语法:**
struct name
{
	type1 varname1;
	type2 varname2;
	.....
};
**(2)调用赋值语法:**
(1)调用赋值语法方法一:用“.”对结构成员进行赋值及调用
		name hzj;					//创建一个name结构类型的hzj
		hzj.varname1=1;			//成员进行赋值
		hzj.varname2=2;
		【防盗标记--盒子君hzj】

(2)赋值语法方法二:
		name hzj={1,2};
注意:定义是单独的,赋值如果是顺序的话可以和在一起写,不然就要分开写

10.类class和对象

类是一个模板,用于定义对象的,方法别称(函数|动词),属性别称(变量|名词)

0、使用类的一个原则

在设计、定义、使用一个类的时候,应该让每个组成部分简单到不嫩挂在简单是最好的,越简单越灵活

1、类和结构体的关系

**(1)使用上**:类似于结构体和定义的关系,先定义结构体再进行结构体的使用,
类似的,先定义一个类,再对类进行使用

**(2)功能上**:结构体只能进行变量数据类型(属性)的组合,
但是类不但可以进行变量数据类型的组合,还可以对功能相关的函数(方法)进行组合
【防盗标记--盒子君hzj】

**(3)实际上**,类是结构体慢慢进化而来的,更具有灵活性,再类中通常把变量成为属性,
把函数称为方法。

2、类和对象的关系

类仅仅是对象的一个雏形模板(必须内容干干净净的),经过过个类的组合完成对对象的描述,
类决定将一个对象打造成拥有什么功能,属性

11.联合union

1、联合定义

联合与结构体有很多相似的地方,也可以容纳多个不同类型的值,
但是联合每次只能储存这些值的某一个,即存放一个值会把上一个值覆盖掉,
用于密码设置等(结构体可以定义多个密码,但是联合只能定义一个)
【防盗标记--盒子君hzj】

2、联合定义语法:

union mima
{
	int birthday;
	char user;
	int &c;
};

3、创建联合类型变量语法:

mima mima_1;

4、联合类型赋值语法:

mima_1.birthday=19961220;【把19961220存入birthday变量中】
mima_1.user="hzj"			 【这时候把hzj存入user的时候会把原来的birthday变量覆盖,做到一改全改】

12.枚举eunm

1、功能

枚举类型用于创建一个可取值的列表,取值也只能在这个列表里面,
否则会出错,编译器会把枚举的元素按照0~N进行顺序排列,
枚举其实是方便给人看的,实质内容也是0~N(功能比数组少一点,但是安全性也会高一点)

2、注意

最好配合switch语句进行使用,避免了字符串的单引号的使用

(1)创建枚举类型:

enum weekdays
{
	monday,
	tuesday,
	wednesday,
	thursday, 
	friday
};

(2)创建枚举变量

weekdays today

【防盗标记–盒子君hzj】

(3)枚举变量赋值

today monday

13.类型别名、const和define

1.const和define的区别

都是宏定义的意思,const比define更高级就行了,**const是静态变量,define是常量**

2.类型别名typedef

功能:作用是为一个类型去一个别名;类似于define,但是**define是针对与常量的,而typedef是针对一个类型的**
--typedef int* intpointer;【把int*取别名intpointer】
--intpointer a					【从此可以直接用intpointer定义一个指针变量a】

. . .

三、C++的模块结构【重要】

1.C/C++操作符

(1)取地址运算符“&”–用于取变量的地址

成员访问运算符“*” --用于把指针变量的地址转化成变量,进行运算
【可以这么理解加*往上层走,加&往下层走】

(2)成员运算符“.”

使用方法:对象.函数(行为),如:cin.peek();意思是cin这个流对象调用了peek()这个函数【区别于C语言中的主函数调用子函数】
"->"解引用符			--针对地址
【指针用"->",对象用"."】

(3)“<<”“>>”操作符

1、在C语言中“<<”是左移操作符
2、在C++语言中“<<”是一个流操作符
【防盗标记--盒子君hzj】
3、这两个流操作符调用了输入输出对象,已经做好了重载,能自动识别整形、浮点型、字符型等等数据结构
4、C语言和C++语言的“<<”含义是不一样的,C++语言对这个"<<"进行了重载,运行C文件是左移操作符,运行C++文件是流操作符

(4)作用域运算符"::"

作用:告诉编译器这个函数是存在在哪里的,或者是属于哪个类的,如
std::cout<<   <<

(5)条件运算符"?:"

尺寸运算符"sizeof"	 

.
.

2.调试及显示的输入输出流

(1)流的概念

1、流有数据流、输入\输出流、视频流,程序流,流程图等等
2、输入流类比:程序指令输入,从键鼠到程序内部,这就是一个输入流,cin<<.....<<
3、输出流类比:屏幕显示输出,从程序内部到屏幕,这就是一个输出流cont<<......<<

(2)print和cout输出流(scan/cin输入流)的区别

print是面向过程的输出,本质是一个函数
cout是面向对象的输出,本质是一个类(输出流对象)
【防盗标记--盒子君hzj】

(3)输出流对象常用的功能函数

cin.ignore(7)					忽略输入的前7个字符
cin.getline(buf,10)			只取输入的10个字符,存放在buf的数组(缓冲区)里
cin.gcout()						检测输入了多少数目的字符
cin.read(buf,10)				只取输入的10个字符,存放在buf的数组(缓冲区)里
cout.write(buf,10)			从缓冲区输出了10个数目的字符

(4)输出流对象常用的用法

cout<

.
.

3.文本读写权限操作及库解释

(1)标准库

#include这个库是输入输出流的库
#include这个库是字符串的库,调用如:std::stream str
这些标准库的**内建功能**非常多,百度一下,绝大部分的功能都能实现的如
--提取字符串
--比较字符串
--添加字符串
【防盗标记--盒子君hzj】
--搜索字符串

(2)传入参数argc\argv[]

argc:整形变量,含义是传入程序的参数数量,包含本身
argv[]:字符指针数组,含义是对应指针指向的文件

(3)文本操作

ifstream in(char*filename,int open_mode)
--ios::in  				其中ios是命名空间,只可读取文件
--ios::out				只可写入
--ios::binary 			以二进制文件打开(如exe文件,还有一种形式文本形式)
--ios::app              在文件末尾追加一个写入的所有数据
--ios::trunk				删除所有文本的所有文件
--“|”用这个分隔符,同时实现多种打开方式,因为in\out这些指令是枚举变量,事先已经由默认值了
(::前面是一个命名空间,后面是他对应的函数)

.
.
.

4.传值、传址、传引用

这里是针对函数的传入参数总结的
【防盗标记–盒子君hzj】

(1)传值(普通变量的值)

默认情况下,C/C++中,被传递到函数的只是变量的值,永远不可能是变量本身
1、函数定义上
	**int changeage(int age)**
2、函数调用上
	**int changeage(age)**,传入的参数为整型数据age
  【这样传入的值和调用的变量对应的上】

.

(2)传址(指针变量的地址)

想要绕开"传值"的问题,最好的办法是拿到变量的地址,变成传址问题,想要获得某个变量的地址很简单,只需要在变量前加上"&"取地址符,如&age。
1、函数定义上
	**int changeage(int *age)**  【这里说明实参输入是地址,因为要赋值在指针上】
2、函数调用上
	**int changeage(&age)**传入参数为age的地址&age
【这样传入的地址刚刚和调用的指针对应的上】
传址注意:如果传过去的是地址必须要用"*"进行解引用,才能操作进行运算,除非你要修改地址

.

(3)引用传递(我常用)

和传址的过程是一样的,形式有点不一样而已
1、函数定义上
【防盗标记--盒子君hzj】
	**int changeage(int &age)**【这里说明实参输入是地址】
2、函数调用上
	**int changeage(age)**【实质传入参数为age的地址&age,这里系统会自动的把age变成他对应的地址,但是优点在于运算是可以把age当变量使用】

(4)注意:

1、形参和实参的不同,形参是被调函数的形式参数,实参是运行函数中实际参数
2、传值调用并不会改变原来的变量的值,但是传址调回用会改变原来的值,因为本质是改地址底层的东西
3、值传递是安全的,址传递是危险的
4、和传址有点迷惑性的

.
.

5.强制类型转换

1、方法

在静态变量前加入(变量数据类型)

2、功能

强制改变变量的的数据类型,来对得上程序的数据结构要求

3、例子:

(int)、(float)、(double)、(class name*)、(char)等等

4、数据类型的运算和强制转换错误

  9/5.0输出的是整数,9。0/5.0输出的是浮点数
  【防盗标记--盒子君hzj】

.
.

6.重载机制及多态性

(1)函数重载定义

实质就是用同样的名字再定义一个有着不同参数但有着同样功能用途的函数(如同一个人,能完成不同的事情一样)
重载可以重载不同数目的参数,也可以重载不同的数据类型

(2)不同的数据类型重载函数实现方法:

改变函数传入的形参数据结构,同时对同一名字而不同数据结构的函数进行声明,系统会自动识别

(3)不同的参数个数的重载函数实现方法:

改变函数传入的形参的数目,同时对同一名字而不同数据结构的函数进行声明,系统会自动识别

(4)好处:

简化工作的编程工作,提高了程序的可读性,所以重载不是面向对象的特征

(5)(类)重载机制

重载机制可以允许定义同名的多个函数(方法),只是这些函数的输入参数必须不同(可以参数的数据类型不同,也可以参数的数量不同),
编译器会自定识别,因为编译器是根据不同的参数输入区分不同的函数(方法)的

注意:重载只能在类本身新定义的函数中进行重载,不能子类中先集成基类的函数再对该继承的函数进行重载,这样会出错的,重载机制只适合用于新定义的函数
【防盗标记--盒子君hzj】

注意区分重载机制和覆盖机制,及其两个机制的作用

(6)(运算符)重载机制

1、重载的定义
重新赋予新的含义,函数重载就是对函数重新赋予新的含义,运算符重载就是对运算符重新赋予新的含义

2、运算符重载的方法:
先定义一个重载运算符函数,在执行被重载的运算符时,系统会自动调用该函数,实现相应的运算

3、运算符重载和函数重载的关系:
运算符重载是通过定义函数实现的,所以运算符重载实质上是函数的重载

4、重载运算符 函数格式一般如下:
函数类型 operator 运算符名称(形参列表)
{
	对重载运算符的实现过程
}
例子:把加法运算符重载成减法运算符
【防盗标记--盒子君hzj】
int operator +(int a,int b)
{
	return(a-b);
}
5、优点:
用重载运算符代替了函数调用的过程,可视化程度更高,仅仅关注运算符的功能就行,不用关心运算符功能的实现
6、注意:
	1、C++不允许用户及定义新的运算符,只能对已有的运算符进行重载
	2、以下蜈蚣丸运算符是不允许重载的。
	--"." 				成员运算符
	--"*"				成员访问运算符
	--"::"				作用域运算符
	--"?:"				条件运算符
	--"sizeof"		尺寸运算符
	3、重载不能改变运算符对象(操作数)个数
	4、重载不能改变运算符的优先级别
	5、重载不能改变运算符的结合性
	6、重载运算符函数不能有默认的参数
	7、重载运算符必须和用户定义的自定义类型的对象一起使用,其参数必须有一个类的对象或者引用。(这个约定是为了防止程序员该标准类型结构的运算符性质)
	8、只有在经常使用,很有必要的时候才重载运算符,因为别人读程序,重载运算符不好理解
	9、重载运算符尽量不要改变他原有的意义,最好是在原有的意义上增加功能 

(7)重载"<<"操作符

通过重载"<<"操作符来实现print打印输出的功能

(8)多态性

1、多态性的解释:
用同一个名字定义冉函数,当调用同一个名字的函数的时候,却执行不同的操作,从而实现了一个接口,多钟方法(函数),理解上可以康丽洁为重载函数的升级版
2、多态性是如何实现的
【防盗标记--盒子君hzj】
--编译时的多态性:重载函数
--运行时的多态性:虚函数

7.全局变量和静态方法static,虚函数和纯虚函数virsual

静态方法:

1、适用场景

当多个对象同时需要某个变量的数据,而该变量数据又不属于某个类class

解决方法一:可以通过吧这个数据定义成全局变量,这样可以解决这个问题,
但是这样存在一个不安全性,因为虽然满足了每个对象的访问级别问题,
但是若果每个对象都能修改这个变量,万一出错就找不到源头,
所以我们不建议在非必要的时候声明使用全局变量

解决方法二:
C++允许我们把一个或者多个变量过着函数声明属于某个类,而不仅仅是该类特有的变量或者函数--静态变量

2、静态方法的使用

在它的声明前面加上static保留字就可以了,声明可以在类中的任何位置,包括:public\protected\private中

3、静态方法的调用语法

(1)可以使用普通函数的调用语法进行调用,但是不建议,如:objectName.methodName();
(2)坚持使用静态类的调用语法:ClassName::methodName();

4、静态方法的注意

(1)static既可以用于变量,和可以用于函数【这就是比全局变量好的地方,static静态变量可以认为是一个全局变量的功能,只是更强大了】
(2)记得要在类声明的外部对静态 属性(变量)做出声明,意思是静态变量要做两次声明【就像声明全局变量一样】,这么做是为了给静态变量分配内存
(3)静态成员是所有对象都可以共享的,所以不能在静态方法里访问非静态的元素【静态方法优先级是比较低的】
(4)非静态方法可以访问类的静态成员,也可以访问类的非静态成员

5、优点

1、程序员可以在没有创建任何对象的情况下调用这个变量和函数【访问级别层面】
2、可以让有关的数据在所有的对象中进行共享						  【数据层面】
【防盗标记--盒子君hzj】

虚方法(virsual method)

1、功能

为了是编译器有选择的调用覆盖的内容的方法(函数 )【相当于调用的优先级提高】

2、使用场景

假如cat和dog是pet的子类,基类中有一个函数play(),
子类cat和dog也有对应的play()并对基类的play()进行了覆盖,
如果在主程序中定义pet *pointer=new cat,并执行cat->play();
结果是输出了pet.play()的 内容。这是不对的

3、注意

虚方法是继承的,如果在基类里把某个函数或者变量声明为虚方法(函数)
,在子类中就不可以在一次声明是虚方法(函数)了,
因为本来已经继承了,已经是虚函数了

4、虚方法的用法

在变量或者函数定义前加上virtual保留字

5、优点

程序员无需顾虑一个虚函数会咋子其某个子类中编辑一个非虚函数

6、经验

(1)如果某个函数拿不准要不要声明为虚方法,那么就把这个函数声明为虚方法
(2)虚方法可能会使程序运行的慢一点,但是安全性高,天使过程不会出现奇怪的现象

**纯虚函数【最抽象的函数,什么都不做就是什么都做了】**
在设计一个多层次 类继承关系时常常用到
【防盗标记--盒子君hzj】
功能:告诉编译器不要浪费时间在这个类中寻找实现函数了,只有在继承的时候才会有实现过程
语法:在声明一个虚方法的基础上,在原型的末尾加上“=0”
virtual void eat()=0;

.
.
.

8.动态内存管理

静态内存

1、定义

静态内存就是包括我们此前一直使用的东西:变量(包括指针变量)、固定长度的数组、给定类的对象。我么可以可以根据变量名字和地址类访问设使用他们

2、静态内存的弊端

(1)我们不得不在编写成虚的时候就分配一块足够大的内存给变量,这会消耗大量的内存
(2)一看程序运行起来,不管实际情况如何,变量占用的内存都是一样的,这也会到时有可能使内存溢出,导致数据错误

动态内存(对于基本类型和对象)

1、使用场景

在很多时候,需要内存数据量的大小是无法事先完全知道的,除了用报错和限制取值范围的方法,这时候就需要用到动态内存管理

2、功能

动态内存支持程序员创建和使用根据具体需要扩大和缩小的数据结构,他们仅仅受限于计算机的硬件内存大小的系统的特殊约束

3、定义

动态内存是有一些没有名字,只有地址和内存块构成的,这些内存是只有在程序运行期间才会动态分配的

动态内存是有标准C++库的“内存池”管理的,从内存池申请一些内存需要使用new语句,
它将根据我们提供数据类型分配一块大小合适的内存(只要我们有足够大的内存空间),
new语句将会返回性分配地址的起始地址
【防盗标记--盒子君hzj】

4、注意

如果计算机的内存已经满了,new语句就会抛出std::bad_alloc的异常警告,为了避免这种情况我们用new申请了一块内存后要用delete把他归还给内存池,
同时还要把用的指针变量设置为null,null指针的含义是不指向任何地址的指针【就是空指针】,这样避免数据泄露
例子:
int *i=new int;		【给指针变量i申请一块整型数据类型的内存空间,指针变量i存放着这块地址的手地址值】
i=null;				【设置指针为空指针】
delete i;

new和delete

1、功能:动态创建过释放一个内存空间,避免运行的时候因为内存不足出错,指针是一种专门用来保存内存地址的数据类型,

方法一:我们以前使用指针的常用的做法是:创建一个普通变量,在创建一个指针变量,把普通的变量的地址赋给一个指针,然后我们就可以用指针变量铜鼓操作地址去访问这个变量了

方法二:在没有创建变量的情况下为有关数据分配内存:即直接创建一个指针变量并让它指向新分配的内存快
int *pointer=new int;			【new用于创建一个内存块,创建一个整形的内存块并用*pointer指向它】
*pointer=110;
std::cout<<*pointer;
delete pointer;				   【delete用于删除一个内存块】
【新的C++新的两个保留字new和delete,程序中每一个new操作都要有一个delete操作与之对应,因为程序不会自动释放内存,会造成程序泄露】

动态数组

1、功能

在程序运行的时候让用户输入一个值自定义数组的长度,int a[???]:
int *x=new int[10];  【动态分配一个整型数据的数组内存给指针数组变量x】
x[0]=45;					【通过数组下标的方式访问指针数组变量x】
【防盗标记--盒子君hzj】
x[1]=100;
删除一个动态数组,要比普通删除一个变量复杂,普通删除一个变量仅仅需要删除该一个变量的地址就行,二删除一个数组是要删除整个数组中所有变量的地址
方法:delete[]x;

避免内存泄露

不是所有系统都想windows一样经常重启,有些像linux系统用于服务器的几年都不关闭的,经常使用new申请内存又不释放,会大量占用计算机的内存,导致系统崩溃
避免内存泄露的推荐做法:
int *x;
x=new int[1000];
delete[] x;
x=NULL;
这么做已经把这块动态内存的地址存放的x彻底还原进去内存池了 

.
.

9.命名空间和模块化编程

(1)命名空间namespace

1、使用背景

编写的程序越多越复杂,就需要用到命名空间,命名空间其实是由用户自己制定义的范围,
同一个命名空间内的东西只要独一无二就可以的,如果某个程序有许多不同的头文件或者已经编译的文件,
而它们有各种声明了许多东西,这时候命名空间可以提供保护,以防变量及函数冲突,
这样不同命名空间里面就可以拥有相同的变量名和函数名了
【防盗标记--盒子君hzj】

2、功能

这是一个命名空间的概念,作用是把C++标准库中所有的标志符(类函数、对象)都定义在同一个特殊的命名空间下,这样可以避免全局变量、局部变量等的冲突

3、方法

先写出关键字namespace,在写出空间名字,最后用一堆花括号把命名空间里面的东西括起来
namespace name
{
	.......
}

4、注意

(1)在最后面不用加分号
(2)如果在程序开头没有写using namespace std;这个指令,还有一个补救的方法:std::cout语法来调用特定的输出流,std::在大型程序中是很有必要的

(2)模块化编程(工厂设计的方法基础):

1、使用背景

把实现的效果划分为多个部分(模块),每个模块写在一个文件里面,
这样把多个模块搞到多个文件中,用编译器把文件重新组合一起实现功能。

2、头文件:后缀名为.h文件

系统头文件功能:声明C++标准库文件 如:#include

3、自定义头文件功能

提供必要的函数声明,变量声明、类声明,使用第三方库声明,
但是千万不要在头文件里面写程序的实现,程序的实现写在C/C++文件里面,如:#include“fish.h”

4、注意

(1)自定义头文件一般都放在一个头文件里进行声明,再调用这个头文件就行了,这样避免重复包含和漏包含的情况,而且会专门创建一个目录(文件夹)分开存放这些头文件,易于查找
【防盗标记--盒子君hzj】
(2)头文件里面尽可能多的注释,因为头文件会被很多文件引用,声明的东西应该描述的更清晰

.
.

10.模板template语法

泛型编程技术支持程序员创建函数和类的模板(template),而不是具体的函数和类

适用范围:
当程序员需要用到这些函数中的某一个是,编译器讲根据模板马上生成一个能够对特定数据类型进行处理的代码版本,这样允许程序员使用一个解决方案解决多个问题。

标准模板库(STL)

11.经验

1、主函数都要有return

因为return是用来推出程序并返回错误信息的,其中return 0代表程序运行没有问题

2、合法性检查

要对数据的输入输出做合法性检查(特别是用户输入的数据),以免输入错误及系统崩溃,检查的是数据类型和取值范围(正负数、特定值)、参数个数等等
这样做事比较耗内存,但是大大增加了程序的健壮性(减少缓冲区溢出的问题)
解决办法:
1、使用switch语句检查特定值
2、用if语句做范围限幅
【防盗标记–盒子君hzj】

3、发布出去的程序都要做压力测试

–有时候内存不够大也会出错
–或者缓冲区不够大
–或者数据类型不对应【重载能够解决】
–狂按enter键,触发了后面的程序(小孩子)
–系统的应用软件崩溃检查

4、程序越简化越好

–面对过程的把实现过程封装起来
–面对对象的把对象封装起来
–面对模块的把组件和一个一个程序文件封装起来
封装程度越高,越高级的程序语言,运行效率越低,要求的硬件越高 (因为要考虑通用性,会预先定义很多东西)

5、for语句可以临时定义一个i

for(int i=0;i<10;i++)

6、要用的变量最好先初始化一遍,避免随机初始化

7、强制转换时在该变量前加一个(数据类型),如(float)a

8、设计程序要考虑通用性(以后可以偷懒)、预错性

【程序看起来成熟很多 ,不能只考虑仅仅实现功能】
【防盗标记–盒子君hzj】
–常用的常量可以用宏定义定义起来,方法一:#define【在函数外】 方法二:const【在函数内】(一改全改)
–检测输入cin是正常的,如果cin为非正常值得时候是0,如:std::cin<

四、C++工具及STL库(刷题的时候常用)

1.STL库

std库提供的是C++语言基础的数据类型,有很多数据类型的内置函数可以用!

STL库提供了C++语言的多种数据结构(容器)和算法实现

容器,即存放数据的地方。比如array等。在STL中,容器分为两类:序列式容器和关联式容器。
序列式容器,其中的元素不一定有序,但都可以被排序。如:vector、list、deque、stack、queue、heap、priority_queue、slist;
关联式容器,内部结构基本上是一颗平衡二叉树。所谓关联,指每个元素都有一个键值和一个实值,元素按照一定的规则存放。如:RB-tree、set、map、multiset、multimap、hashtable、hash_set、hash_map、hash_multiset、hash_multimap。

vector:它是一个动态分配存储空间的容器。区别于c++中的array,array分配的空间是静态的,分配之后不能被改变,而vector会自动重分配(扩展)空间。
set:其内部元素会根据元素的键值自动被排序。区别于map,它的键值就是实值,而map可以同时拥有不同的键值和实值

2.矩阵运算库eigen3

Eigen3充分利用了C++的模板类操作、内置的命名空间eigen函数丰富能够快速定义、声明一个任意的m*n的矩阵,并且库里class类兼容几乎所有的矩阵运算,使用起来很是方便
【防盗标记–盒子君hzj】

3.LCM轻量级通讯库

4…

面试相关的概念

C++语言与数据结构、算法的关系

数据结构与算法是不依赖任何一种语言的,对于C++ 语言,它有自己的语法和调用系统的机制
所以说,C++和数据结构与算法是两个方面的内容
.

c语言和c++有什么区别

C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛。C++支持多种编程范式 --面向对象编程、泛型编程和过程化编程。 其编程领域众广,常用于系统开发,引擎开发等应用领域,是最受广大程序员受用的最强大编程语言之一,支持类:类、封装、重载等特性!

C语言是结构化的编程语言,它是面向过程的,而C++是面向对象的。

1、面对过程,面对对象

2、封装、 继承、多态
封装:将数据和函数等集合在一个单元中(即类)。被封装的类通常称为抽象数据类型。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

继承:继承主要实现重用代码,节省开发时间。它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向派生类的基类指针,来调用实现派生类中的方法。有编译时多态和运行时多态。

C++的继承性体现【公有继承、受保护继承、私有继承的区别】

(1)公有继承时,派生类对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有和受保护成员;

(2)私有继承时,基类的成员只能被直接派生类的成员访问,无法再往下继承;

(3)受保护继承时,基类的成员也只被直接派生类的成员访问,无法再往下继承。

C++的多态性体现

多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数 。C++多态性主要是通过虚函数实现的,虚函数允许子类重写override(注意和overload的区别,overload是重载,是允许同名函数的表现,这些函数参数列表/类型不同)

在绝大多数情况下,程序的功能是在编译的时候就确定下来的,我们称之为静态特性。反之,如果程序的功能是在运行时刻才能确定下来的,则称之为动态特性。C++中,虚函数,抽象基类,动态绑定和多态构成了出色的动态特性。

1)类class、虚函数virtual、类模板、重载等等

2)运行时多态性:通过虚函数实现,虚函数:虚函数允许子类重写override,用于定义同一功能,类似实现的一个父类函数

3)编译时多态性:通过重载函数实现
.

类模板、函数模板的概念

函数模板特例化

引入原因:编写单一的模板,它能适应大众化,使每种类型都具有相同的功能,但对于某种特定类型,如果要实现其特有的功能,单一模板就无法做到,这时就需要模板特例化。

定义:是对单一模板提供的一个特殊实例,它将一个或多个模板参数绑定到特定的类型或值上。

函数模板特例化的方法
必须为原函数模板的每个模板参数都提供实参,且使用关键字template后跟一个空尖括号对<>,表明将原模板的所有模板参数提供实参。
声明函数模板

  template <typename T>  
  void fun(T a)  
 {  
      cout << "The main template fun(): " << a << endl;  
 } 

定义和使用函数模板

template <>   // 对int型特例化  
void fun(int a)  
{  
  cout << "Specialized template for int type: " << a << endl;  
}  

 int main()  
 {  
     fun<char>('a');  
     fun<int>(10);  
     fun<float>(9.15);  
     return 0;  
}  

对于除int型外的其他数据类型,都会调用通用版本的函数模板fun(T a);对于int型,则会调用特例化版本的fun(int a)。注意,一个特例化版本的本质是一个实例,而非函数的重载。因此,特例化不影响函数匹配

类模板的特例化
声明类模板

   template <typename T>  
   class Test{  
   public:  
       void print(){  
           cout << "General template object" << endl;  
       }  
   };

定义和使用函数模板

template<>   // 对int型特例化  
 class Test<int>{  
 public:  
     void print(){  
         cout << "Specialized template object" << endl;  
     }  
 }; 

另外,与函数模板不同,类模板的特例化不必为所有模板参数提供实参。我们可以只指定一部分而非所有模板参数,这种叫做类模板的偏特化 或部分特例化(partial specialization)
.

C++空类默认有哪些成员函数

默认构造函数、析构函数、复制构造函数、赋值函数

.

C++中类与结构体的区别

继承机制、权限机制

最本质的一个区别就是默认的访问控制: struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的。

“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。
实现一个新的数据类型我常用结构体这种方式,组合已有的数据类型

.

C++中结构体和联合体的区别

结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,
联合中只存放了一个被选中的成员(所有成员共用一块地址空间),
结构体的所有成员都存在(不同成员的存放地址不同)

.

纯虚函数、虚函数的作用

纯虚函数的理解
纯虚函数是为你的程序制定一种标准,纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现, 带纯虚函数的类抽象类,这种类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。

虚函数可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,而不是基类中定义的成员函数(只要派生类改写了该成员函数)。若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都会调用基类中定义的那个函数。虚函数是C++多态的一种表现,可以进行灵活的动态绑定。

纯虚函数是为你的程序制定一种标准,纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。

class A{
protected:
void foo();//普通类函数
virtual void foo1();//虚函数
virtual void foo2() = 0;//纯虚函数
}

带纯虚函数的类抽象类,这种类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。

虚函数是为了继承接口和默认行为

纯虚函数只是继承接口,行为必须重新定义

.

内联函数和普通函数的区别

内联函数要做参数类型检查, 内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的压栈出栈的开销,提高效率。

内联函数是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到那里去。对于短小简单的代码来说,内联函数可以带来一定的效率提升,而且和C时代的宏函数相比,内联函数 更安全可靠。可是这个是以增加空间消耗为代价的
.

析构函数的作用(避免内存泄露)

析构函数是用来释放delete所定义的对象中使用的指针、内存空间,打开了文件等等系统功能的
构造函数与对应的析构函数就可以避免内存泄露
内存泄漏是指向系统申请分配内存进行使用(new),但是用完后不归还(delete),导致占用有效内存。
在类的构造函数和析构函数中没有匹配的调用new和delete函数

如果是自己写析构函数的话,如果你的类里面分配了系统资源,如new了内存空间,打开了文件等,那么在你的析构函数中就必须释放相应的内存空间和关闭相关的文件;这样系统就会自动调用你的析构函数释放资源,避免内存泄漏

析构函数是用来释放所定义的对象中使用的指针,默认的析构函数不用显示调用,自建的析构函数要在程序末尾调用

如果你的类里面只用到的基本类型,如int char double等,系统的默认析构函数其实什么都没有做

但如果你使用了其他的类如vector,string等,系统的默认析构函数就会调用这些类对象的析构函数
.

重载与重写的区别

重载:是指允许存在多个同名函数,而这些函数的参数表不同
重写:是指子类重新定义父类虚函数的方法

.

常用的设计模式

1、单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点;
2、工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类
.

智能指针是什么?智能指针怎么实现?什么时候改变引用计数?

什么是智能指针
智能指针的一种通用实现技术是使用引用计数。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。
 
当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。

每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)

智能指针的实现
构造函数中计数初始化为1;
拷贝构造函数中计数值加1;
赋值运算符中,左边的对象引用计数减一,右边的对象引用计数加一;
析构函数中引用计数减一;
在赋值运算符和析构函数中,如果减一后为0,则调用delete释放对象

auto_ptr类与shared_ptr类

从c++11开始, auto_ptr已经被标记为弃用, 常见的替代品为shared_ptr。shared_ptr的不同之处在于引用计数, 在复制(或赋值)时不会像auto_ptr那样直接转移所有权。 两者都是模板类,却可以像指针一样去使用。只是在指针上面的一层封装。

auto_ptr
auto_ptr实际也是一种类, 拥有自己的析构函数, 生命周期结束时能自动释放资源,正因为能自动释放资源, 特别适合在单个函数内代替new/delete的调用, 不用自己调用delete,也不用担心意外退出造成内存的泄漏。

atuo_ptr的缺陷:

auto_ptr不能共享所有权,即不要让两个auto_ptr指向同一个对象(因为它采用的是转移语义的拷贝,原指针会变为NULL)。
auto_ptr不能管理对象数组(因为它内部的析构函数调用的是delete而不是delete[])。
auto_ptr不能作为容器对象,STL容器中的元素经常要支持拷贝,赋值等操作,在这过程中auto_ptr会传递所有权。

shared_ptr
shared_ptr 使用引用计数的方式来实现对指针资源的管理。同一个指针资源,可以被多个 shared_ptr 对象所拥有,直到最后一个 shared_ptr 对象析构时才释放所管理的对象资源。

.

数组指针和指针数组的区别

https://blog.csdn.net/men_wen/article/details/52694069
.

指针常量和常量指针

https://www.zhihu.com/question/19829354
https://blog.csdn.net/xingjiarong/article/details/47282563

.

指针和引用的区别

引用是变量的一个别名,内部实现是只读指针

引用只能在初始化时被赋值,其他时候值不能被改变,指针的值可以在任何时候被改变

引用不能为NULL,指针可以为NULL

【指针是变量】指针只是一个变量,只不过这个变量存储的是一个地址;
【引用是别名】引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已,不占用内存空间。
引用&和取地址符&很像
指针可以为空,但引用不能为空
.

C++函数中值的传递方式有哪几种?

三种传递方式为:值传递、指针传递和引用传递。

.

如何实现类对象只能静态分配或动态分配?

C++中建立类的对象有两种方式:

(1)静态建立,例如 A a;
静态建立一个类对象,就是由编译器为对象在栈空间中分配内存。使用这种方法,是直接调用类的构造函数。

(2)动态建立,例如 A* p = new A();
动态建立一个类对象,就是使用new运算符为对象在堆空间中分配内存。这个过程分为两步:第一步执行operator new( )函数,在堆空间中搜索一块内存并进行分配;第二步调用类的构造函数构造对象。这种方法是间接调用类的构造函数。

.

避免内存泄露的方法【C++的内存管理】

内存溢出,内存泄漏的原因?
内存溢出是指程序在申请内存时,没有足够的内存空间供其使用。原因可能如下:

内存中加载的数据量过于庞大,如一次从数据库取出过多数据
代码中存在死循环或循环产生过多重复的对象实体
递归调用太深,导致堆栈溢出等
内存泄漏最终导致内存溢出
内存泄漏是指向系统申请分配内存进行使用(new),但是用完后不归还(delete),导致占用有效内存。常见的几种情况:
(1) 在类的构造函数和析构函数中没有匹配的调用new和delete函数

1、一般的变量在作用域中结束了生命周期会自动释放内存
2、使用new分配的内存块需要,手动delete 释放掉,同理使用malloc分配的内存块需要,手动free 删除掉

栈: 存放函数参数以及局部变量 , 在出作用域时 , 将自动被释放 . 栈内存分配运算内置于处理器的指令集中 , 效率 很 高 , 但分配的内存容量有限 .

堆 :new 分配的内存块 ( 包括数组 , 类实例等 ), 需 delete 手动释放 . 如果未释放 , 在整个程序结束后 ,OS 会帮你回收掉 .

自由存储区: malloc 分配的内存块 , 需 free 手动释放 . 它和堆有些相似 .

全局/静态区: 保存自动全局变量和static变量(包括static全局和局部变量)。静态区的内容在整个程序的生命周期内都存在,有编译器在编译的时候分配(数据段(存储全局数据和静态数据)和代码段(可执行的代码/只读常量))。

常量存储区: 常量 (const) 存于此处 , 此存储区不可修改 .

.

关键字new与malloc的区别

new/delete是C++的运算符。都可用于申请动态内存和释放内存。

malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
.

关键字extern的作用

extern置于变量或函数前,用于标示变量或函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义【定义的时候用过后,声明就不要在重复了】
.

关键字static的作用

static修饰变量或者函数时,使得被修饰的变量成为静态变量,不可被改变,在作用域的生命周期完了的时候内存自动会被释放
.

关键字define的作用

宏在预处理阶段替换,const在编译阶段替换;宏没有类型,不做安全检查,const有类型,在编译阶段进行安全检查
.

关键字const的作用

定义变量为只读变量,不可修改
const成员函数【形参不能被修改】(只需要在成员函数参数列表后加上关键字const,如char get() const;)
不可以同时用const和static修饰成员函数

const与#define的区别:宏在预处理阶段替换,const在编译阶段替换;宏没有类型,不做安全检查,const有类型,在编译阶段进行安全检查
.

关键字register的作用

请求CPU尽可能让变量的值保存在CPU内部的寄存器中,减去CPU从内存中抓取数据的时间,提高程序运行效率。
.

关键字volatile的作用

用来修饰变量的,表明某个变量的值可能会随时被外部改变,因此这些变量的存取不能被缓存到寄存器,每次使用需要重新读取。
.

关键字typedef的作用

给数据类型定义一个新名字

.

头文件中的ifndef/define/endif 是干什么用的

防止头文件被重复包含
.

Makefile文件的作用

makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
.

main 函数执行以前,还会执行什么代码?

全局对象的构造函数会在main 函数之前执行。
.

原子操作的概念【有点汇编语言指令的味道】

操作系统原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断,分为两种情况(两种都应该满足)

(1) 在单线程中, 能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。

(2) 在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
.

线程和进程的联系和区别

(1)进程是程序的一次执行,线程是进程中的执行单元;

(2)进程间是独立的,这表现在内存空间、上下文环境上,线程运行在进程中;

(3)一般来讲,进程无法突破进程边界存取其他进程内的存储空间;而同一进程所产生的线程共享内存空间;

(4)同一进程中的两段代码不能同时执行,除非引入多线程。
http://blog.csdn.NET/wolenski/article/details/7969908
.

线程有哪几种状态

http://blog.csdn.Net/wolenski/article/details/7969908.

进程间的通信方式

管道、有名管道、信号、共享内存、消息队列、信号量、套接字、文件.

.

线程同步和线程互斥的区别

http://blog.csdn.net/wolenski/article/details/7969908
.

TCP和UDP有什么区别

TCP—传输控制协议,提供的是面向连接、可靠的字节流服务。

 当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。

 TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

.

 UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。

 UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。

 由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

stl库提供什么样的容器(数据结构)?

.

vector和队列的区别是什么?

.

优先级队列有什么用?

.

堆和栈的区别

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)― 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) ― 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收

.

自动数据类型auto

auto的自动数据类型能够根据数据定义生成不同的数据结构。
.

关于sizeof的认识

sizeof计算的是在栈中分配的内存大小。常用于计算数组的长度
.

使用过的 shell 命令

cp , mv , rm , mkdir , touch , pwd , cd , ls , top , cat , tail , less , df , du , man , find , kill , sudo , cat
.

使用过的 vim 命令

wq!, dd , dw , yy , p , i

.

.

.

.

.


参考资料

c/c++格式规范参考ROS规范
http://wiki.ros.org/CppStyleGuide

你可能感兴趣的:(C++,python语言语法,c语言,c++,开发语言)