C++msbs
2021-02-02 07:16
标签:临时对象 复制 set deque img 属性 表示 iterator rtu 1. 虚函数与纯虚函数 虚函数是允许被派生类重新定义的成员函数 虚函数是为了实现动态绑定(基类能创建自己的对象) 纯虚函数使一个类称为抽象类(不能创建对象的类,即这个类只是作为一个模型出现),派生类只继承这个接口 2. 基类析构函数声明为虚函数 为了防止内存泄漏。通过父类指针去销毁子类对象时,如果析构函数不是虚函数,则不会触发动态绑定,只调用基类析构函数回收了基类对应的空间,派生类的析构函数没有被调用。 3. 自增运算符 i++:创建临时变量存储i的值,i增加1,然后返回临时变量的值 ++i:i增加1,返回这个i(并且这个表达式是左值) 4. vector (1)size和capacity size指的是当前实际元素个数 capacity指的是vector中能容纳的元素个数 (2) reserve让容器预留空间,增加了vector的capacity,没有改变size resize需要两个参数(容器新的大小,新插入元素),如果没有第二个参数,就用默认构造函数插入这个元素,vector的size被改变了 5. 关于类里面 const、static static对变量产生的作用: 对局部变量,改变了其存储位置和生命期。存储位置从栈中变成静态存储区,其生命原来是随着语句块结束而消失,加了static则在整个程序运行期间都存在。但其作用域是没有改变的。 对全局变量,改变了其作用域,使得该变量只在本文件内可见 (1)static数据成员的初始化 static数据成员存储在静态存储区上, 而不是栈上 static数据成员的初始化要在类体外面(静态成员属于整个类,而不属于某个对象,如果在类里面初始化,会导致每个对象都包含这个静态成员) 不能在头文件中初始化(会导致重复定义) static变量在main函数之前初始化(普通全局变量、静态全局变量、类静态成员变量都在main之前初始化) static成员可以成为成员函数的参数 (2)const数据成员 const成员变量意思是对每个对象而言,它是常量且每个对象的这个值可以不同,但对类而言是可变的 const成员变量只能用构造函数初始化列表的方式初始化 (3)static const数据成员 static const整型可在类内初始化 static const其他类型包括浮点等要在类外初始化 (1)static修饰成员函数 该成员函数没有了this指针,只操作static变量,与对象没有关系 (2)const修饰成员函数 表示该函数不会修改对象的数据(通过const this *) (3)不能用static和const同是修饰成员函数 因为static函数没有this指针,所以同时用两个修饰没有意义,编译器也会报错 ----- 数据成员初始化顺序: 列表初始化方式:与定义成员变量的顺序有关 const成员变量必须在构造函数初始化列表中初始化 类的static成员变量,只能在类外初始化 基类、派生类成员变量初始化: 基类静态变量、全局变量 派生类静态变量、全局变量 基类成员变量 派生类成员变量 6. 指针和引用 (1) 指针是一个新的变量,存储另一个变量的地址。是间接操作另一个变量 引用不是变量,只是一个别名,对引用的操作是直接操作在该引用关联的变量上 (2) 就指针而言,有指向常量的指针 int const *p ,有指向不可变的指针常量 int *const p 引用只有指向常量的引用 int const &a=b 而引用的指向本来就不可变 (3) 指针有多级指针,引用只有一级 指针可不初始化,引用必须初始化 sizeof指针,得到指针变量所占空间,一般4字节 sizeof引用,得到其指向变量/对象大小 自增运算符运算意义不一样 7. 多态 含义:一个接口,多种方法 目的:接口重用【封装:模块化 继承:代码扩展】 (1)静态多态/早绑定 函数重载:函数名一样,返回值、参数个数、类型不一样 编译期间确定调用哪个 (2)动态多态/晚绑定 通过虚函数实现 运行时才确定调用哪个 用基类指针调用虚函数,根据指针实际指向对象类型调用相应的函数 (3)虚函数表 类有虚函数时,则类会有一张虚函数表(表的每一项是一个虚函数的地址) 类的每个对象有一个指向虚函数表的虚指针(位于对象地址前面) 派生类有兼容基类的虚函数表,如果重写了一个虚函数,则在其虚函数表里面对应位置的函数地址替换为重写的函数地址 8. new和malloc new是运算符;malloc是库函数(一个语言的编译器能控制运算符) new会调用构造函数,delete会调用析构函数; malloc、free不会 new返回具体类型的指针;malloc返回void *指针 new可被重载;malloc不能 9. C++内存分区 代码区:存放二进制代码 字符串常量区 全局和静态区:全局变量、静态变量存储 堆区:malloc、new从这里申请空间 栈区:存放局部变量 10. 常用容器 vector:基于数组 deque双端队列:类似数组加链表的组织形式,使用起来类似数组或队列 list双向链表、forward_list单向链表 array:固定大小数组 string map、set:无重复、有序 基于红黑树(插入、删除效率高) multimap、multiset:可重复、有序 基于红黑树(插入、删除效率高) unordered_map、unordered_set:无重复、无序 基于哈希表(查找效率高) unordered_multimap、unordered_multiset:可重复、无序 基于哈希表(查找效率高) 11. 内存泄漏 可能场景: 忘记释放动态申请的内存空间 基类析构未声明为virtual 系统资源忘记释放 解决: 重载new、delete 使用智能指针:shared_ptr、weak_ptr、unique_ptr 12. C++11新特性 (1)auto类型推导、decltype 用auto类型变量接收很复杂的类型: auto不能用于函数传参 decltype为了解决auto只能对变量进行类型推导的不足出现的,可判断表达式的类型: (2)for循环 (3)lambda函数 捕捉列表能捕捉上下文中的变量供函数使用 mutable:取消默认的lambda的const属性,使函数体内能修改变量(不影响外部得到变量) (4)override、final关键字 在某个应该被子类重写的函数后加上override,表明这个函数是重写的虚函数 在类名字后面加final或在函数后面加final,表明这个类不希望被继承,不希望这个函数被重写 (5)智能指针 将基本类型指针封装为类对象指针,并在其析构函数里编写delete语句删除指针指向的内存空间 (6)右值引用 例子: 第三行用x初始化a,则会调用相应的拷贝构造函数,进行深度拷贝 第四行用x+y初始化b,实际上创建了一个临时变量,然后用这个临时变量初始化b,但是这个临时变量随机就丢弃了 第五行用一个返回非引用类型的函数的返回值初始化c,也是用一个临时对象接收返回值,然后初始化c 上面x是左值 第四和第五行的参数是右值,表达式产生了string的匿名对象/临时对象,然后用临时对象初始化,然后丢弃临时对象,这样实际上多做了操作,通过右值引用简化流程。如下:修改构造函数,入参为右值引用 通过浅拷贝,将临时对象的地址复制给b或者c,然后将临时对象指针置空,充分利用了这个临时对象,这个构造函数也叫 "转移构造函数" (7)空指针nullptr C中空指针常量NULL宏定义为0或 (void *)0,任意类型指针都可转换为 void *类型 C++中别的类型指针不能与void *类型指针转换,且NULL宏定义为 0 C++中0有了两个含义:整型数值0和NULL为了避免重载函数调用时二义性,定义了nullptr表示空指针来替代NULL (8)线程支持 (9)构造函数 委托构造:可在一个构造函数后调用另一个重载的构造 (10)新增容器 ①std::array 保存在栈中,编译时创建固定大小的数组 不能隐式转换为指针: ②单向链表 forward_list ③无序容器四个 ④元组tuple 固定大小的不同类型元素的集合 (11)正则表达式 (12)其他 ..... 13. const和define (1)起作用时间不同 define在预处理阶段起作用,进行替换 const在编译阶段起作用 (2)类型检查 define不进行类型安全检查 const有数据类型,编译时进行类型检查 (3)内存空间 define不分配内存 const需要在静态存储区中分配空间 14. 悬空指针和野指针 悬空指针:所指向对象被释放,但指针变量的值未赋值空 野指针:没有初始化的指针变量,值不确定 15. sizeof和strlen (1)功能 sizeof是运算符,用来计算一种类型所占内存大小 strlen是函数,参数为char *,计算以‘\0‘结尾字符串的长度,且不包括‘\0‘ (2)只有用字符数组比较这两个才有意义 16. 字节对齐 (1)结构体 比如int为4字节的情况下,一般是4字节对其 (2)联合体 联合体所占空间与最宽成员及其他成员都有关系:①大小足够容纳最宽的成员 ②大小能被其所有成员基本类型的大小整除 u1类型需要空间16字节 u2类型只要8字节 17. 类型转换 (1) 18. 计算类大小 class A{}; sizeof(A)==1 class A{virtual Fun(){}} sizeof(A)==4(32位) 8(64位) class A{static int a;}; sizeof(A)==1 class A{int a;}; sizeof(A)==4 class A{static void fun(){}}; sizeof(A)==1 类中static声明的成员变量不计算类的大小中 19. 大小端 大端big endian:低地址存放高位字节 小端little endian:第地址存放低位字节 数0x12 34 56 78在内存中存放形式为:地址从左到右变大 大端:0x12 0x34 0x56 0x78 小端:0x78 0x56 0x34 0x12 20. C++中 * 和 & 同时使用 参数是一个Node类型指针的引用,在函数里面,不仅可通过p的值改变其指向的内容,也可以改变实参的值 举例:一个单链表反转,head指针指向第一个结点,反转后需要其指向原链表最后一个结点 ①通过指针的指针实现 ②传入指针的引用 21. C++中堆和栈比较 (1)数据结构中的堆结构和栈结构 栈:先进后出的结构 堆:有大根堆和小根堆。大根堆是根结点值最大,且根结点的两个子树也是堆。用来实现优先队列,保证队列最前面的数是最大或最小的,每次取走一个数,堆调整结构,使得最前面的依然是最大或最小的 (2)内存分配中的栈和堆 这里的堆不是数据结构中说的堆 ①增长方向 栈向下(向较低地址)增长;堆向上(向较高地址)增长 ②申请方式 栈由编译器自动管理;堆需要编写程序的人主动申请 ③效率 栈分配较快;堆申请较慢 ④大小限制 栈能获得的空间较小,且是连续的内存区域;堆能获得的空间较多,且不连续(链表管理) 22. 空类 编译器为空类自动生成 默认无参构造函数、默认拷贝构造函数、默认拷贝赋值运算符、默认析构函数 23. 不能写成虚函数的函数 (1)普通函数 非成员函数的普通函数只能重载 (2)友元函数 友元函数不属于类的成员函数,不能被继承,不能写成虚函数 (3)构造函数 构造函数用来初始化对象里面的成员,而基类构造不知道派生类有哪些成员 (4)内联成员函数 内联函数在编译时展开,而虚函数在运行时绑定 (5)静态成员函数 编译时确定,无法动态绑定,不支持多态 24. 一个string类的简答实现 25.分配内存的方法 (1)malloc void *malloc(unsigned int size) 申请分配长度size字节的连续空间,空间内容没有初始化 (2)calloc void *calloc(unsigned int num,unsigned int size) 申请分配num*size字节的空间,并初始化内存空间为0 (3)realloc void *realloc(void *ptr,unsigned int size) 申请分配size字节空间,并把内存空间首地址赋值给ptr,不会初始化 (4)new 申请分配空间,调用构造函数实现初始化 26. vector中直接访问和at访问 vec[i]可能有越界风险 vec.at(i)会抛出异常 C++msbs 标签:临时对象 复制 set deque img 属性 表示 iterator rtu 原文地址:https://www.cnblogs.com/taoXiang/p/12796556.htmlvirtual 返回类型 func(参数);
virtual 返回类型 func(参数)=0;
for(vectorint>::const_iterator itr=vec.cbegin();itr!=vec.cend();++itr)
for(auto itr=vec.cbegin();itr!=vec.cend();++itr)
auto x=1;
auto y=2.01;
decltype(x+y) c;
int a[5]={1,2,3,4,5};
for(int &x:a) {
coutendl;
}
[捕捉列表] (参数) mutable -> 返回值类型 {函数体}
string x = "abc";
string y = "def";
string a(x);
string b(x+y);
string c(fun()); //fun函数返回一个字符串string (string && tmp)
{
浅拷贝
}
arrayint,4> a={1,2,3,4};
int len=4;
arrayint,len> b={1,2,3,4}; //错误,编译期间需要能确定大小
void fun(int *p,int n)
{
for(int i=0;i
fun(a,4); //错误,a不能被隐式转换为指针
fun(&a[0],4);
fun(a.data(),4);string src[]={"aa.txt","a2.txt","123.txt","a334g.jpg"};
regex re(".*[0-9]\\.txt");//以数字结尾的txt
for(auto &x:src) {
cout":"endl;
}
char a[]="abc";
sizeof(a); //4
strlen(a); //3
union u1{
int n;
char a[11];
double b;
};
union u2{
int n;
char a[5];
double b;
};
void fun(Node * &p);
Node * fun(Node **head)
{
if(NULL == *head || NULL==(*head)->next) {
return *head;
}
Node *p1 = *head;
Node *p2 = p1->next;
Node *p3 = NULL;
(*head)->next = NULL;
while(p2 != NULL) {
p3 = p2->next;
p2->next = p1;
p1 = p2;
p2 = p3;
}
*head = p1; //修改实参的值
return p1; //或者返回该值
}
Node *head = initList();
head = fun(&head); //通过传入指针的地址改变了实参head的值
//现在head是指向新的头结点,,即原链表的最后一个结点
void fun(Node *&head)
{
if(NULL==head || NULL == head->next) {
return;
}
Node *p1 = head;
Node *p2 = p1->next;
Node *p3 = NULL;
head->next = NULL;
while(p2!=NULL) {
p3 = p2->next;
p2->next = p1;
p1 = p2;
p2 = p3;
}
head = p1;
}
Node *head = initList();
fun(head);
class A{};
class A{
public:
A();
A(const A&);
~A();
A& operator=(const A&);
};
class string{
public:
string(const char* str);
string(cosnt string &other);
~string();
string & operator=(const string &other);
private:
char *data;
};
//***********************//
string::string(const char *str) {
if(NULL == str) {
data = new char[1];
*data = ‘\0‘;
}
else {
int len = strlen(str);
data = new char[len+1];
strcpy(data,str);
}
}
string::string(const string &other) {
int len = strlen(other.data);
data = new char[len+1];
strcpy(data,other.data);
}
string::~string(){
delete [] data;
}
string::string& operator=(const string &other)
{
if(this==&other) {
return *this;
}
delete [] data;
int len = strlen(other.data);
data = new char[len+1];
strcpy(data,other.data);
return *this;
}
上一篇:python函数递归-实例
下一篇:Java中的锁