C++——第一章 基本语言

PS:仅供自己记录笔记,使用到时进行记录,不具有参考性。

1. 命名空间

(1) 定义

命名空间目的就是为了防止名字冲突,看成作用域。

namespace mySpace
{
void func()
	{
	// do smt
	}
}
(2) 命名空间名可以不连续
  • 命名空间可以写在多个文件,如果以往未定义过命名空间,那么namespace 命名空间名相当于定义了一个命名空间;
  • 如果以往定义了这个命名空间,那么就相当于打开已存在的命名空间并为其添加新成员的声明。
(3) 外界访问命名空间

命名空间名::实体名,如:mySpace::func();
使用方法:

// test1.h 中声明
namespace mySpace
{
	void func();
}
// test1.cpp 中定义
namespace mySpace
{
	void func()
		{
		// do something
		};
}

// main.cpp 中调用
using namespace mySpace;
func();
// 或者
mySpace::func();

2. 局部变量及初始化

int abc=5; 不是赋值,是定义的时候初始化。也可以int abc{5}; int abc={5};
注意:int abc=3.5f; //丢了0.5 被系统截断,int abc{3.5f}; //无法编译成功,系统执行了一个从浮点数到整数的转换。
数组初始化:int a[] {1,2,3,4,5};

3. auto

变量类型自动类型推断,声明时要赋予初值[初始化],发生在编译期间,auto不会造成程序效率低。

4. 头文件防卫式声明

防止多个头文件相互include,导致声明重定义。
在每头文件中加上:

// 头文件名为: head1.h
// 条件编译
#ifndef __HEAD1__H__    //如果没有定义
#define __HEAD1__H__	//则定义
	// 程序
#endif

5. 引用

为一个变量齐起了另外一个名字。 并不额外占用内存,引用和原变量占用同一块内存。
定义引用的时候必须初始化,不然给谁起别名。
必须绑定到变量和对象,不能给常量起别名。
必须类型相同。

int a = 10;
int &refa = a;

可以给变量传参(引用传参),改变变量。

6. 常量 const

(1)不变的量。

const int var = 7;一种承诺,表示一般不会去改变。
constexpr :也是常量的概念,在编译的时候求值,提升性能。

(2) const cahr *, char const *, char * const区别:
  • const char *p; p指向的东西不能通过p来修改(p 所指向的目标,那个目标中的内容不能通过p来改变。)
  • char const * 等价于const cahr *
  • char* const p; p一旦指向了一个地址,就不可以再指向其他地址了。
(3)函数形参中带const,防止无意中修改了形参值导致实参值被无意修改。实参类型更灵活。

void func(const student &stu){}

7. 范围for语句

int v[] {1,2,3,4,5,6};
for(auto &x:v)  // 使用引用&省去拷贝,提升效率
{
// do smt
}

8. 动态内存分配问题

(1) C++中的内存区域
  • 栈(stack): 函数内的局部变量存放在这里,由编译器自动分配和释放。
  • 堆(heap): 程序员malloc/new分配,使用free/delete释放。忘记释放后,系统会回收。
  • 全局/静态存储区: 存放全局变量和静态变量static。程序结束时系统释放。
  • 常量存储区: const,“I LOVE CHINA!”
  • 程序代码区:
(2)堆和栈不同用途和区别:

栈: 空间是有限的。但是分配速度快,程序员控制不了。
堆: 只要不超过实际拥有的物理内存,操作系统允许你能够分配的最大内存大小之内。分配速度比栈慢。

C语言中使用malloc/free, C++使用new/delete.

(3) new的一般使用格式
  • 指针变量名 = new 类型标识符: int* myInt = new int;
  • 指针类型名 = new 类型标识符(初始值) ,圆括号表示初始值。int* myInt = new int(18);
  • 指针类型名 = new 类型标识符[内存单元个数],int* pa = new int[100]; // 开辟一个大小为100的整型数组空间,释放:delete[] pa;

有new必须有delete,不要重复释放,释放前做个 if 判断。

9. nullptr

nullptr代表空指针, NULL实际就是0,对于指针初始化使用nullptr。
int* ptr = nullptr;

10. 结构体

(1)定义
// 定义
struct student {
	int number;
	char name[100];
}
// 使用
student myStudent; //或 struct student myStudent; 可以省略struct 直接使用结构名
myStudent.name = "xiaosan"; // myStudent->name = "xiaosan";

C++ 结构体不仅能定义成员变量,还能定义成员函数。

(2)结构体初始化的方式:

1)冒号初始化:student myStudent={number:123, name:"xiaosan"};
2) 顺序初始化:student myStudent={123, "xiaosan"};
3) 构造初始化:通过结构体的构造函数进行初始化结构体对象。

struct student {
  student(int number, char name)
  {
  this->number = number;
  this->name = name;
  }
  int number;
  char name[100];
} 
// 初始化
struct student myStudent(123, "xiaosan");
(3)结构体的赋值:

1)依次给每一个结构体成员变量赋值:struct student myStudent; myStudent.number=123; myStudent.name="xiaosan";
2)使用已有的结构体变量给另外一个结构体变量赋值。
student myStudent={number:123, name:"xiaosan"};
student yourStudent;
yourStudent = myStudent;

11. 权限修饰符

(1)对于 结构体/类 中的成员变量和成员函数(对象)。

public: 外部能够访问。
protected: 可以通过类内部、子类内部、友元函数friend 访问,不能通过类对象访问,即外部访问。作用:基类(父类中)中的某个函数不想对外暴露,但是想被子类访问,使用protected
private: 可以通过类内部、友元函数friend 访问。不能继承到子类中访问。

(2)结构体默认是public, 类默认是private
(3)子类继承父类时也有public, protected, private 三种继承方式,class student: public people {};

继承方式的不同,会决定子类继承到属性访问权限的变化。 在这里插入图片描述

12. 类简介

(1)结构体和类的区别:

1) 结构体默认public,类默认private。
2) 结构体继承默认是public,类继承默认是private。
一般的,使用到函数时用类,只用到成员变量使用结构体,如定义bbox的xywh时。

(2)类的组织结构:

类的头文件(.h)声明类和对应的成员变量、对象,在.cpp中进行实现/定义类及其成员变量、对象。在其他.cpp中调用该类时,直接include。
在这里插入图片描述

13. 内联函数inline

(1)inline void addNum(int a, int b){}; 在编译阶段系统尝试将调用该函数替换为函数本体,用于提升性能。一般inline函数为比较简单的函数,不超过5~10行更好,一般inline该函数内部使用for, switch不划算。
(2)在类中,在头文件定义实现函数时,该函数自动变成内联函数。内联函数的定义就要放在头文件中。

14. string

(1)定义和初始化string对象

#include<string>, std::string str;
1) string s1; 默认初始化, s1=“”; 空串,表示里面没字符。
2)string s2 = "xiaosan";
3)string s3("xiaosan");
4)string s4 = s3; 拷贝初始化

(2)string对象上的操作

1)判断是否为空:str.empty();
2)str.size(); / str.length(); 返回字节/字符数量,代表该字符串的长度。 每个中文是两个字节,英文是一个字节。
3) str[i]
4) s3 = s1 + s2;
5) s1 == s2
6) s1.c_str() 返回一个字符串s1中的内容指针,返回一个指向正规c字符串的常量指针,也就是以\0结尾的。 引入是为了与c语言兼容。
const char *p = s1.c_str();
7) 遍历字符串

string s1 = "xiaosan";
for(auto &c: s1)
{
c = toupper(c);
}

15. vector

(1)定义和初始化vector

vector<int> intSet; 表示保存的是int类型的集合/数组。不能装引用即vector<int &> 这个是错误的。

1)空vector:使用vec.push_back(i) 或者 vec.emplace_back(i)
push_back :先创建元素,在移动拷贝元素到vector末尾。 emplace_back:直接在vector末尾创建元素。 一般来说使用emplace_back,效率更高。

2)元素拷贝初始化
vector<string> mystr2(mystr); 或者 vector<string> mystr2 = mystr;

3)列表初始化
vector<string> mystr = {"a", "b", "c", "d"};

4)创建指定数量的元素。有元素数量概念的东西,一般会用圆括号。
vector<int> ijihe(15, -200); 创建15个int类型的元素,每个元素都是-200。
vector<string> sjihe(5, "hello"); 创建5个string类型的元素,每个元素都是"hello"。
不给初始值:vector<int> ijieh(20); 20个元素,每个元素值都为0。

5)多种初始化方式。
vector<int> i1(10); 表示10个元素,每个元素缺省值为0.
vector<int> i1{10}; 表示1个元素,这个元素值为10.
vector<string> s1{10}; 表示10个元素,每个元素缺省值为"",自动转换了。
vector<int> i1(10); 表示10个元素,每个元素缺省值为0.

(2)vector对象的操作
  • vec.empty()
  • vec.size() :返回元素个数。
  • vec.clear() :将容器清空。
  • 赋值:vec2 = vec1; vec2的值为vec1,vec2的值被vec1冲掉。
  • ==, != 两个vector相等,元素数量相等,对应位置元素值也得一样,否则就是不等。
  • 循环遍历: for(auto &i: vec). 需要注意的问题:在循环遍历vector时,在里面做了对vector元素的操作,比如插入元素,这样会导致错误。在遍历一个容器中,千万不要改动vector容器的容量,增加、删除都不可以。
(3)vector内存释放
  • vector的内存空间只会增长,不会减小。比如一个vector占用了10000个字节,erase掉9999个,留下一个有效元素,但是实际内存占用仍为10000个,vector内存在vector析构时才能被系统回收。所以即使使用clear,vector所占用的内存空间依然如故,也无法保证内存的回收。
  • vector.size() 为当前vector拥有元素的个数,vec.capacity()为实际占用内存的个数,一般capacity是>=size的。
  • 清空元素:vec.clear()
  • 释放内存:使用swapstd::vector<std::string>().swap(pred_frames_vector);

16. 迭代器

迭代器是一种遍历容器元素的数据类型,可以理解成指针,迭代器用来指向容器的某个元素。

(1)容器的迭代类型

vector<int> iv = {1,2,3};
vector<int>::iterator iter; 定义迭代器,理解成一个类型,专门应用于迭代器。

(2)迭代器begin(),end() , 反向迭代器rbegin(), rend()
  • begin(),如果有元素,指向容器中第一个元素。
    • end(),指向的不是末端元素 ,指向的是容器末端元素的后边。
  • for(vector<int>::iterator iter=vec.begin(); iter!=vec.end(); iter++){ cour<< *iter <<endl;}

在这里插入图片描述

(3)迭代器运算符
  • *iter: 返回迭代器iter所指向元素的引用。
  • iter ++ 让迭代器指向容器中的下一个元素。
(4)const_iterator:表示指向的值不能改变,但是可以改变指向哪个元素,更像常量指针。只读。
  • **cbegin()和cend()**操作,返回的值常量迭代器。
(5)迭代器失效

使用迭代器遍历容器,改变容器容量(增加/删除),会使迭代器失效。每次更新迭代器,可以避免。

17. 类型转换static_cast

(1)隐式类型转换

int m = 3 + 5.6; 结果为8,系统自动截断小数部分,结果还是int类型。

(2)显示(强制)类型转换——static_cast
  • C语言强制转换风格:int k = 5 % (int)3.2; (int)3.2 和int(3.2)一样。
  • C++:强制类型转换名(express)。int k = static_cast<int>(f);
  • static_cast和隐式类型转换一样。
  • 在类中,子类转换为父类,使用static_cast
  • void* 与其他类型的指针之间转换。
  • 一般不能用于指针类型之间的转换,如int*,double*,float* 之间的转换。
(3)显示(强制)类型转换——dynamic_cast

运行的时候进行类型识别和检查,主要用于父类型和子类型之间转换用的。

(4)显示(强制)类型转换——const_cast

去除指针或引用的属性,该转换能够将const性质转换掉。

(5)显示(强制)类型转换——reinterpret_cast

重新解释,将内容解释为另一种不同的类型。常用于将一个整型(地址)转换为指针,一种类型指针转换成另外一种类型指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值