基础

命名空间

作用:命名空间将全局作用域分成不同的部分

        不同的命名空间中的标识符可以同名不会产生冲突                                   

        命名空间可以相互嵌套

        全局作用域也叫默认命名空间

作用域限定符比命名空间优先级高

命名空间使用:两种方法1.::2.using namespace 

c++里面使用c语言,头文件stdio.h或者cstdio

C语言和C++的不同

1.for循环

可以在for循环里面定义变量

2.寄存器变量

不能频繁添加,寄存器很小

C语言寄存器变量无法取地址,C++可以取寄存器变量地址,强行取地址,register无效

3.全局变量

C语言可以重复定义多个全局变量,同名的全局变量会被链接到全局数据区的同一块地址上

C++不允许重复定义全局变量

4.结构体

空的结构体,C语言的sizeof为0

C++里面sizeof为1

C语言结构体是一个集合(直接Test t1错误,需要添加struct),C++结构体是一种类型(可以直接写Test t1)

5.函数

函数不定义类型,C语言默认int,C++必须有返回值类型

bool类型

真是1,假是0,大小为1

条件运算符

引用

变量名

访问变量的两种方式:变量名,地址

引用:一个变量的别名

&两个含义,定义的时候,表示引用,前面没有类型,取地址

引用在定义的时候一定要初始化

int &k;
k = num;   //错误

引用的大小取决于引用的对象

结构体,没有初始化,不正常的语法情况考虑到引用的本质:指针

不管什么类型,引用都在变量前面

void init(char *&s)
{
    malloc(128);    //此处操作指针s等价于操作main函数中的str
}

int main()
{
    char *str;
    init(str);
    strcpy(str,"hello");
}

函数返回引用

1、跟返回局部变量的地址一样,不能返回局部变量的引用; 2、可以返回全局变量的引用; 3、使用引用来接函数的返回值。

常量指针和指针常量

函数

*****

1、C语言允许函数不写返回值;函数括号内不写参数表示能接受任意类型和个数的参数; 2、C++要求函数必须写上返回值;函数括号内不写参数表示不接受参数。

默认参数:一旦形参开始使用默认参数,后面都要使用默认参数

占位参数:不能用,但是调用的时候必须要传一个

int func(int a,int b,int);
int func(int a ,int b,int = 0);     //占位参数和默认参数的结合

重载函数 

判断标准:参数个数不同,参数类型不同,参数顺序不同

!!函数返回值不能作为重载函数的标准

 匹配规则:1.精确匹配实参2.通过默认参数匹配实参3.通过默认类型转换匹配实参

匹配失败原因:1.有歧义

类和对象

面向对象:只有对象内部的代码能够操作对象内部的数据

对象只存储成员变量

特点:抽象(抓住事物的本质,而不是内部具体细节或具体实现)

        封装(把对象的属性和操作结合在一起,构成一个独立的对象,限制属性和操作的权限)

        多态

        继承

优点:易维护,可读性高,现成的库,效率高,易扩展

缺点:编码效率高,运行效率低于C语言

类和结构体的区别:

类默认私有,私有只可在类里面用

结构体默认公有

类的实现方式:头文件(尽量写函数的声明但是不要去实现他)

面向对象案例:点和圆的关系

构造函数:

构造函数是特殊的成员函数,名字与类名相同,创建对象时由编译器自动调用,以保证每个数据都能有一个合适的初始值,并且在对象整个生命周期只调用一次。

默认,无参,有参,拷贝构造函数

调用无参函数不带括号

指向字符串常量,前面必须加const,所以第一个const必须加

可以不用初始化set

没有返回值

构造函数的特性

1.构造函数名与类名相同

2.构造函数为无返回值类型

3.对象实例化时编译器自动调用相对应的构造函数

4.构造函数支持函数重载

5.无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。
 

析构函数destruct

内存泄漏,有malloc必须要free

没有返回值,没有参数

对象被释放时,自动调用析构函数

浅拷贝和深拷贝

浅拷贝:地址也拷贝一样的,不能释放两次内存

深拷贝:拷贝地址指向的内容,自己再申请一块内存。

凡是涉及地址,重写拷贝构造函数,用深拷贝、

对象初始化列表 

类的成员变量加上const,只读变量

构造的顺序

对象初始化列表使用场景:

场景1:类的成员变量被const修饰

场景2:类对象作为另一个类的成员变量没有提供无参构造函数

场景3:基类没有提供无参构造函数

匿名对象:

手动调用,即创建匿名对象

构造中不要调用构造函数,容易产生匿名对象

new和delete

堆空间不会调用构造函数和析构函数,尽量不要用malloc和free

static静态成员变量

C语言中,修饰局部变量(延长声明周期),全局变量(限定作用域在本文件),函数(同全局)

静态成员变量,共享一块地址内存,一定要在类的外部初始化(分配空间)

静态成员函数

单例模式

运用static,静态成员函数和静态成员变量

面向对象模型

对象所占的大小,就是成员变量所占的大小,可以看作结构体

函数是共享的

const修饰的成员函数为常函数,只要函数不涉及修改函数,尽量加上const

友元函数和友元类

 

继承和派生

一个类从一个类获取成员变量和成员函数的过程

使用继承的两种典型场景:

1.创建新类与现有的相似,只是多出若干成员变量和成员函数

2.创建多个类,有很多相似 的成员变量和成员函数,提取公共成员

继承成员变量,需要把父类成员变量权限改为protected

继承权限决定继承的成员变量的权限

权限等级:public> protected>private

继承的权限不能超过继承权限,只能降级,不能升级

默认public最好,继承来的数据放在前面

创建派生类对象,一定会先调用基类构造函数

基类,派生,派生,基类

构造顺序:基类,成员,再自己

同名成员变量

基类和派生类有同名成员变量,默认隐藏继承来的,调用派生类的

若调用继承来的,用::作用域

派生类和基类一样,同样共享一个静态变量

多继承

构造顺序:按照继承的顺序来,哪个在前面,哪个先

多继承的问题:二义性(Base TestA TestB TestC)

A继承base,b继承base,c继承AB,此时C里面有两个base(浪费空间),无法区分c.base,需要加限定符明确A的还是B的

需要添加作用域限定符

解决方法,继承的时候添加virtual

:virtual public Person

虚基类指针,本身占8个字节

每个指针只能指向自己的部分

防止通过指针访问其他的成员变量

class TestA : virtual public Base

 向上转型

可以把派生类赋值给基类

可以把派生类指针赋值给基类指针,基类指针赋值给派生类对象

可以把派生类引用赋值给基类引用

多态

同一条语句能表现出多种形态

三个条件:1.要有继承,2.虚函数重写3.要有基类指针指向派生类对象

p是parent * 类型,调用parent基类的show

但是创建的派生类对象 ,理应调用派生类,所以在基类和派生类里面加上virtual(派生类可加可不加),此时不属于静态联编

指向基类对象时,show调用基类

重载和重写的区别

             运行期间根据具体对象类型决定调用的函数

多态原理

凡是有虚函数的类,里面都有虚函数表

不要把所有的函数声明成虚函数,调用效率低。

构造函数调用虚函数

构造顺序,先构造父类,再构造子类

构造函数无法实现多态

基类指针

父类指针指向子类数组,由于父类与子类p++步长不同,不要混搭

所以不要用基类指针指向派生类数组

虚析构函数

析构函数尽量写成虚析构函数,通过虚析构函数,可以释放派生类对象

动态类型识别

 当不明确派生类类型时,可以用基类指针,指向派生类对象

到底能不能强转:p指向派生类可以转换,指向基类对象不能转换

多个枚举常量,中间用逗号隔开,最后一个不要加分号enum{}

三种方法:1.自定义类型2.动态类型强转dynamic_cast<强转类型>(强转对象)(必须多态才能使用)3.typeid

<1>

使用虚函数进行动态识别的缺陷:

1.必须从基类开始提供类型虚函数

2.所有派生类都必须重写类型虚函数

3.每个派生类的ID必须唯一

<2>

 <3>

 获得指向对象的类型

测试变量是声明类型的 

有关键字type_info,要有头文件typeinfo

 抽象类

实例:圆,矩形,三角形……

这一类事物的统称,不能写但必须要存在,例如求图形的面积(基类)

类似函数声名

如果派生类里面继承了抽象类,但没有重写虚函数,那个函数也会被认作纯虚函数,那个派生类也叫抽象类

C++中没有Java中的接口概念,抽象类可以代替接口问题

g++ *.cpp -o main -Wall

运算符重载

输出运算符<<只能重载成全局函数:左操作数不能修改

输入运算符>>istream

+可以全局或者成员函数(返回值是常量,常量不能给一般引用初始化)

=类可以直接赋值类

涉及到地址的,都要深拷贝

能作为左值的函数,都是引用=    <<   >>    []    +=     

 如何判断返回引用还是普通变量?

1.看该运算符能不能作为左值使用,如果可以,返回引用;

2.输入输出运算符支持链式编程,函数返回值充当左值,需要返回引用

3.无法修改左值时,使用全局函数进行重载

4.=,[],(),->只能通过成员函数重载

<< >> 前置++ []

相同类型的结构体不支持相加减

本质是函数的重载

运算符能重载成成员函数,也能被重载成全局函数

类型  类名 ::operator  符号(参数)

返回值 函数名(形参)

限制:不能重载的运算符   .     ::     .*     ?:     sizeof

原则:不改变优先级,不改变结合性,不改变操作数,不能创建新的运算符

输出运算符

 赋值运算符

可以当左值,采用引用

重载成成员函数,涉及地址的拷贝,用深拷贝

自增运算符

后置++不能返回引用,后置++有个占位参数

前置++可以返回引用

下标运算符[]

函数调用运算符()

//类里面重载函数调用运算符,创建的对象称作函数对象(回调函数)

逻辑运算符 

不能重载

本质就是函数的重载,重载了但是违背了短路原则,所以不要重载

mystring

string表示字符串

string name;

 智能指针:4个

auto_ptr,shared_ptr,weak_ptr,unique_ptr  相当于模板类

自动释放所指向的对象(包含头文件memory)

uniue唯一,只能一个指向一个对象

模板

模板:两次编译

因此模板调用和编译在同一个文件里

函数模板

建立一个通用的函数,函数类型和形参类型不具体指定

其他都一样,只有类型不一样

template<typename T类属>或者<class T1,class T2>

隐式调用和显式调用 

函数模板不会自动类型转换,普通函数可以自动类型转换(1,‘a') 

注意:

1.函数模板可以被重载

2.C++优先考虑普通函数

3.如果函数模板可以产生更好的匹配,选择模板、

4.如果通过空模板实参列表的语法限定编译器只能通过模板匹配

show<>(1);

这样肯定调用模板

函数定义和调用必须在同一个文件里、

排序模板函数 

搭配运算符重载

冒泡排序

类模板

类模板必须显式调用

模板继承

 模板类派生普通类

模板类派生模板类

注意!派生类访问基类模板的成员变量,加上this 

静态 

涉及到模板类,一定要加<>

 上面是4,下面是3

模板声明

 全局函数,也可以写在里面

在类里面注意改成U

也可以直接在类里面写全局函数,但注意还是全局 

 hpp文件

:sp 文件名,打开另一个文件

ctrl ww切换文件光标到另一个文件

当模板的调用和定义分开来时,一个文件用hpp文件,这样方便整合到一起

强转

C语言强转存在的问题(过于粗暴,难于定位)

C++分成了四类

static_cast用于普通类型的转换,不能用于普通指针类型的转换,用于有继承关系的类指针之间的转换,用于有继承关系的类之间的转换

reinterpret_cast1.用于指针类型的转换,2.指针与普通的转换

dynamic_cast 类层次之间的转换

const_cast  用于去除const属性

引用会分配内存

5523地址相同,const保存在符号表里面,强行对常量取地址会强行分配内存,和引用的内存是同一块,地址取值里面都是3

异常

把函数调用 和函数处理分开来

throw

try  

catch

错误通过异常会向上抛出 

异常跨域函数

异常不会自动类型转换

异常类对象 

 抛出的对象,赋值给捕获的对象,通过拷贝的方式实现

对象 ,引用,指针

一般用引用来接,不会构造,少占用

推荐使用引用

异常案例

异常库 

catch(exception &e)
{
    cout << e.what() << endl;
}

文件 

输入输出流

标准输入

cin是对象

文件存放在磁盘上,程序在内存上运行,读文件叫输入(从输入文件数据传给程序),写文件就是输出(从程序传给输出文件)

cin.getline()获取一行,包括空格

cin.ignore()忽略前面几个元素,然后再获取

cin.peek()从缓冲区读一个字节,但是保留在缓冲区

cin.putbach()把字符写入缓冲区

标准输出

输出要求指定格式,1.使用控制符的方法2.使用流对象的有关成员函数

 成员函数

 

width宽度,字符长度不够,前面空着,后面写原来的

文件操作

STL概述

标准模板库

六大组件:算法algorithm,容易,迭代器iterator,仿函数function object,适配器adaptor,空间配置器allocator

通过迭代器可以实现容器和算法的无缝衔接

每用一个容器,包含一个头文件

容器

所有容器都是模板类

vector向量

是动态数组,可以随机存取元素[]或者at(),尾部添加移除元素很快,头部和中部插入移除费时

采用模板类实现

 插入操作

insert

显示操作

1.迭代器,反应的是地址

 2.【】或者at()

deque双端数组

数组名是首元素地址,不能改变,deque可以改变首元素地址

deque.push_back(elem); // 在容器尾部添加一个数据
deque.push_front(elem); // 在容器头部插入一个数据
deque.pop_back(); // 删除容器最后一个数据
deque.pop_front(); // 删除容器第一个数据 (是引用,可作为左值)

deque的大小

 删除(迭代器)

死循环了,因为deque删除之后数组哪边少,移动那边,最后会移动end,再执行++,it指向it后面了,所以利用返回值

 栈stack和队列(没有迭代器)

不支持遍历

出栈不反悔元素,要查看元素只能用top

list双向链表容器

不可以随机存取元素,不支持at()函数与[],it++可以,it+5不可以

是相当于指针->

priority_queue优先队列(没有迭代器)

是个模板类,默认用的vector也可以deque,不是用的队列

<>里面都是类型,less是模板类,重载了()

less或者greater<>

数据放入容器中,不需要指定位置,会自动排序

和队列差不多,头文件是queue

set集合容器

树形结构

set插入数据比较多,且需要排序的时候用

不能指定插入位置,不可以直接存取元素at.()和[]

multiset和set区别:前者可以元素重复,后者不可以,只能出现一次

插入新元素必须删除之前的

迭代器,对于复杂的类型,可以直接写auto

erase()一个元素,一个区间

insert()

查找按照排序的重载,提高了查找的效率,进去按照学号排序,查找按照学号查找

find返回一个迭代器

 两个迭代器封装在pair里面

map

可以通过迭代器遍历

it是个指针

插入用insert和map[]

区别:insert插入重复会报错,map[]会覆盖

删除

位置,元素,区间

总结

 有对应关系,选择map,只是单一数据排序,set

算法

头文件algorithm,numeric,functional组成

算法里带if,是指条件

谓词

for_each不可以修改,transform可以修改数据

查找

find返回元素迭代器

绑定了第二个参数变成4

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐