0.初识C++
我们可以视C++ 为一个语言联邦,在C++中包含了这样几大块:C语言(以C语言为基础)、Object-Oriented C++(面向对象)、Template C++(泛型编程)、STL (标准模板库)
1.C++标准输入输出
- 标准输入输出头文件:iostream
- 输入:cin >> 变量名
- 输出:cout << 变量名
- 换行并清空输入缓冲区:endl
2.C++标准库和std命名空间
C++标准库的头文件是没有扩展名的
C++标准库可以分为两部分:
(1)标准函数库:
这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承C语言。
(2)面向对象类库:
这个库是类及其相关函数的集合。
- std命名空间:C++标准中引入命名空间的概念是为了解决不同模块或者函数库中相同标识符冲突的问题。标准C++库中的所有组件都在std这个命名空间中声明和定义的。
using namespace std;
// 打开std命名空间
3.作用域运算符,命名空间
(1)作用域:
- 作用域:变量在程序中起作用的范围,分为全局作用域、局部作用域、语句作用域
- 作用于优先级:范围越小优先级越高
- 作用域运算符:
::
取得哪个作用域的内容。可用来区分同名的成员。 - 同一个作用域中不允许存在两个同名的变量
(2)命名空间:
命名空间是用来组织和重用代码的编译单元。之所以出来这样一个东西,是因为人类可用的单词数量太少,并且不同的人写的程序不可能所有的变量都没有重名现象,对于库来说,这个问题尤为严重
- 语法:
namespace 命名空间名称
{
//声明
//变量
//函数
}
- 使用不同命名空间有什么好处呢:比如同名的一套变量如果之后要修改的话,就可以通过using namespace只换一个命名空间来实现,而不需要逐个去修改
4.new-delete动态分配空间
在C++中,通常使用new和delete来动态申请和释放空间(堆区),相当于在C语言中用的malloc和free
(1)new
new申请空间一般使用格式:
类型 * 指针变量名 = new 类型;
int *p = new int; //在堆区分配一块int空间
delete p;
p = NULL;
类型 * 指针变量名 = new 类型(初始值);
int *p = new int(123); //在堆区分配一块int空间,初始化为123
delete p;
p = NULL;
类型 * 指针变量名 = new 类型[内存单元个数];
int *p = new int[10]; //在堆区分配一个整形数组
delete[] p;
p = 0;
(2)delete
delete删除空间使用格式:
delete 指针变量名
; //释放单个的空间delete[] 指针变量名
; //释放数组空间
注意:
- 删除一个指针p(delete p;)实际意思是删除了所指向的目标(变量或对象等),释放了它所占有的堆空间,而不是删除了p本身
- 内存泄漏(memory leak)和重复释放
5.范围for
C++11中包含一种新的for循环,称为基于范围的for循环,可以简化对数组元素的遍历
格式如下:
for(TypeVarName:Array)
{
//每个元素的值会一次赋值给VarName
}
auto
可以在声明变量的时候根据变量的初始值的类型自动为此变量选择匹配的类型
int a = 10;
auto au_a = a; //自动类型推断,au_a为int类型
例如:
int arr[] = {1,2,3,4,5};
for(int val : arr)
{
cout << val << " ";
}
6.缺省函数参数
C++ 中可以在声明函数时定义缺省函数值来减少一些编程工作。
// 函数声明
void VoidMessage(char *pMessage,int nLength = 1,int nColor = 0);
//函数定义
void ShowMessage(char *pMessage,int nLength,int nClolr)
{
cout << " " << nLength << " " << nColor;
}
//函数调用
ShowMessage("long");
//输出结果
long 1 0
- 注意:
(1)默认实参必须在参数列表的结尾
(2)默认参数只能出现在函数声明或者定义二选一中
(3)缺省值必须是常量或者全局变量
(4)缺省参数必须是值传递或者常参传递
7.函数重载
当同一类功能的函数,只是部分细节不同(如参数的个数或者类型不同)时。
利用函数重载机制可以将这些函数取成相同的函数名,从而使程序易于阅读与理解,方便记忆和使用。
void Area(double r);
void Area(double l,double h);
- 调用的时候会根据传入的参数选择调用相应的函数
8.引用
(1)引用:
- 引用是C++引入的新的语言特性,他是某一变量(目标)的一个别名。
用于在程序不同部分使用两个以上的变量名指向同一地址空间。使得对其中任一个变量的操作实际上都是对同一地址单元进行的。 - 引用的声明方法:
类型 & 引用名 = 目标变量名;
声明引用时,必须同时对其进行初始化。
(2)引用的应用:
- 引用的一个重要作用就是作为函数的参数。以前的C语言中函数参数传递是值传递,如果有大块数据作为参数传递的时候,采用的方案往往是指针,因为这样可以避免将整块数据全部压栈,可以提高程序的效率。但是现在(C++)中又增加了一种同样有效率的选择(在某些特殊情况下有时候是必须的选择),就是引用。
//定义一个引用
int a = 100;
int& k = a;
//交换值函数
void Swap(int &x,int &y)
{
int temp = x;
x = y;
y = temp;
}
int main()
{
int a = 100;
int b = 200;
Swap(a,b); //实际上在值传递的过程中进行了int& x = a;int& y = b;的操作,操作xy,就相当于直接操作ab
}
- 常引用,语法:
const 类型 & 引用名 = 目标变量名;
用这种方式声明的引用,不会通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。 - 引用作为返回值,语法:
类型 & 函数名 (形参列表);
用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
(3)引用的注意事项:
- &不是求地址运算,而是起标识作用。
- 声明引用时,必须同时对其进行初始化。
- 引用一旦被初始化就不能再重新引用其他的空间。
- 声明一个引用不是新定义了一个变量,它只表示该引用名时目标变量的一个别名,对引用进行操作实际上就是对被引用变量进行操作。
- 不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。
- 没有NULL值的引用,必须保证“引用”引用的是合法的存储单元。
9.bool类型
布尔类型(bool)是C++新增的一种基本数据类型,在标准的C语言中并未定义bool类型(C99之后有)
- bool类型的变量有两个值true或false表示“是”和“否”。
- bool是C++内置的数据类型,一个字节
10.string类
string是C++中的字符串
- 字符串对象是一种特殊类型的容器,专门设计来操作的字符顺序。传统数组中的字符序列,我们称之为字符数组,而C++字符串对象属于一个类,这个类有很多内置的特点,操作方式更直观,更可靠。
用法:
- 定义字符串:
string str
- 复制和拼接字符串:使用=进行复制,用+进行拼接。
- at()函数:返回下标为n的元素的引用
例如:string str = "hello"
则str.at(2)
取到的值就是'l'
,str.at(0)
取到的值就是'h'
记一个小知识点:at()函数和[]的区别
at() 是 string 类的一个成员函数,它会根据下标来返回字符串的一个字符。与[ ]不同,at() 会检查下标是否越界,如果越界就抛出一个异常;而[ ]不做检查,不管下标是多少都会照常访问。
11.类与对象
(1)面向对象和面向过程
- 面向过程:程序 = 数据结构 + 算法
- 面向对象:程序 = 对象 + 对象 + ... 对象
对象 = 数据 + 算法 - 面向对象胆大特点:
封装、继承、多态
(2)类:
- 类是一种复杂的数据类型,它是将不同的类型的数据和与这些数据相关的操作封装在一起的集合体。
- 类的定义格式:
class 类名
{
访问修饰符:
成员属性;
成员方法;
};
- 访问修饰符:
public
:公共的 任何地方都可以见到
private
:私有的 只有在本类中可以见到
protected
:保护的 只有在本类和派生类中可以见到 - 空类:
空的类的大小是一个字节,作用是用来占位,非空的类实际大小是类中成员变量所占字节的大小 - 成员属性:定义对象的时候分配空间,每个对象各有一份
- 成员函数:编译器存在于代码区,共有一份,所有对象共用一份
(3)对象:
- 对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单元。
- 对象的定义格式:
类名 对象名;
(4)注意事项:
- 在类体中不允许对所定义的数据成员进行初始化;
- 类是抽象的,不占用内存,而对象是具体的,占用存储空间;
- 类中的数据成员的类型可以是任意的,但是自身类的对象是不可以的,但是自身类的指针变量是可以的。
(5)接口函数:
- 链接对象中数据与外部用户的一个工具,使用户通过接口函数对对象内部的数据进行修改等操作。
(6)构造函数:
- 作用:给类中的成员属性进行初始化
- 格式:
类名 () { 内容 }
- 何时调用:在定义对象的时候调用
- 注意可以通过函数重载去定义带函数的构造函数,在定义类的时候就需要给定参数
(7)析构函数:
- 作用:当一个对象生命周期结束时,其所占有的内存空间就要被回收,这个工作就由析构函数完成,析构函数就是“反向”的构造函数。
- 格式:
~类名() { 内容}
- 注意:析构函数没有返回值也没有参数,一个类中只能有一个析构,没有定义析构,类中会有一个默认的析构函数。
12.对象的种类
(1)栈区的对象:
- 使用示例:
{
CPerson per;
}
//当程序走到所到作用域的}的时候调用析构函数
- 生命周期:作用域
(2)堆区的对象:
- 使用示例:
CPerson* per = new CPerson;
delete per;
per = NULL;
//当程序遇到delete时调用析构函数
- 生命周期:从new开始,到delete结束
(3)全局对象:
- 使用示例:
//在main函数外边定义的
CPerson per;
- 生命周期:知道程序退出
(4)临时对象:
- 使用示例:
CPerson();
- 生命周期:仅限于这一代码行
- 临时对象的应用:
看下面这种情况:
CPerson Show()
{
CPerson pp; //这里的pp这个对象是一个栈区对象,当return的时候就被回收了
return pp;
}
int main()
{
CPerson ps = Show();
return 0;
}
在main函数里面调用Show这个函数的时候就需要返回一个值,但是在Show函数里面定义的对象是一个栈区对象,在return的时候就要回收,那么拿什么返回呢?实际上这里就用到了临时变量,在调用这个函数返回的时候在栈区对象被回收之前就定义了一个临时对象去拷贝栈区对象用来返回,这个临时对象只用在调用函数的这一代码行进行一个返回的操作,当程序到下一个代码行的时候临时变量就被回收了。
13.new/delete和malloc/free
我们试运行这样两段代码:
CPerson ps = new CPerson;
delete ps;
ps = NULL;
CPerson* ps = (CPerson*)malloc(sizeof(CPerson));
//ps->CPerson::CPerson();
//ps->CPerson::~CPerson();
free ps;
ps = NULL;
我们会发现当使用new/delete的时候自动调用了CPerson类的构造和析构函数,而当使用malloc/free的时候,没有调用构造和析构函数,所以由此可以看出,malloc/free只是简单地申请空间和释放空间,而new/delete申请和释放空间的时候还会触发构造和析构函数
如果你使用malloc/free的话就要自己手动去调用构造析构函数了,如上注释中内容,注意调用构造函数的时候必须要加上类名作用域,析构函数可以不加,规范起见可以两个都加。
14.this指针
(1)类中的成员属性和成员函数什么时候存在:
- 成员属性:定义对象的时候分配空间,每个对象都有一份空间
- 成员函数:编译期存在,存在于代码区,只有一份,所有对象公用一份代码
(2)this指针
看下面例子:
class CPerson
{
public:
int a;
public:
CPerson(int b)
{
a = b;
}
public:
void show()
{
cout << a << endl;
}
};
int main()
{
CPerson AA(100);
AA.show();
CPerson BB(200);
BB.show();
return 0;
}
输出结果为:100 200
那么就有一个问题:前面说所有对象共用一个代码段,对象有两个,变量a也有两个,但是函数只有一份,那么函数是如何区分被哪个对象调用的?输出的a是哪个对象的呢?
实际上show函数有个隐藏的参数this,show函数实际上是这样的: show(CPerson* this)
哪个对象调用,就将哪个对象的地址传进去,在函数中使用的变量实际上都是由this指针指向的这个变量,即:
show(CPerson* this)
{
cout << this->a << endl;
}
好啦,第一篇先更到这里,还会有第二篇续集哦,欢迎持续关注!
标签:函数,int,笔记,学习,对象,CPerson,C++,引用 From: https://www.cnblogs.com/fau152/p/17218394.html