学习c++简单笔记

最近重新学习c++,附上学习过程中简单记录的一些笔记。
只是个人学习,比较简陋,仅供参考,欢迎补充。


c++三大特性:封装、继承、多态

常量
1.#define 宏常量
2.const 修饰变量

标识符命名
1.不能是关键字
2.字母、数字、下划线
3.第一个字符不能是字母
4.区分大小写

数据类型
1.整形:short(2),int(4),long(4/8),long long (8)
2.浮点型:float(4),double(8)
小数默认double型,使用float时在数字后面加f
默认情况下,输出小数显示6位有效数字
科学技术法:3e2 =3*10^2
3.字符型:char (1)
ASCII A(65),a(97)
4.字符串:char [];string(需要添加string头文件)
5.布尔型:bool (1) true-1;false-0

随机数:

#include <ctime>
srand((unsigned int)time(NULL));
rand()%100;//  0-99随机数
rand()%100+1;// 1-100

循环
for(0;1;3)
{2}
break退出循环, continue跳过循环

数组(数组名就是首地址)
数组占用内存sizeof(arr)
数组首地址arr
第一个元素地址&arr[0]

冒泡排序:
排序总轮数=元素个数-1
每轮对比次数=元素个数-排序轮数(从0开始)-1

二维数组
1.arr[2][3]=1……
2*.arr[2][3]={{1,2,3},{4,5,6}}
3.arr[2][3]={1,2,3,4,5,6}
4.arr[][3]={1,2,3,4,5,6}

指针
1.定义指针 :数据类型*指针变量名 int *p = &a;
2.使用指针 :通过解引用的方式找到指针指向的内存 *p==a
3.占用地址 :32位操作系统下,所有数据类型的指针,都占4个字节;64位下,占8个字节
4.空指针:用于指针初始化;不可以访问(0-255之间内存编号是系统占用) int *p = NULL;
5.野指针:指针指向非法空间
6.const
常量指针:指针指向可以修改,指针指向的值不可以修改
const int *p = &a
指针常量:指针指向不可以修改,指针指向的值可以修改
int *const p = &a
指针指向、指针指向的值都不可以修改
const int *const p = &a
7.地址传递:可以改变实参数据;值传递不会改变实参的值

结构体
定义:struct 类型名称 {成员列表};

赋值
string seed = “abcd”
arr[i].name = “name_”
arr[i].name+=seed[i]


核心编程

$内存分区模型
(运行前:代码区、全局区)
1.代码区:存放机器指令;共享(频繁执行)、只读(防止意外修改)
2.全局区:全局变量、static静态变量、常量(字符串常量、const全局常量)
局部变量和局部常量const不在全局区(栈区)
数据在程序结束后由操作系统释放
3.栈区:数据由编译器管理开辟和释放
不要返回局部变量地址,栈区数据在函数执行完成后自动释放
4.堆区:new开辟内存
new返回该数据类型的指针
int *p = new int (10)
delete p
int * arr = new int [10] :10代表有10个元素
delete[] arr

引用:数据类型 &别名 = 原名 int a = 10;int &b = a;
1.引用必须初始化
2.引用一旦初始化后,就不可以更改
引用传递:形参会修饰实参 void swqp(int &a,int &b)
引用的本质 指针常量
const int &ref = 10; 防止误操作

$函数
默认参数:如果传入数据,使用传入的数据;没有传入,使用默认值
注意:
1.如果某个位置有了默认参数,那么从这个位置往后都必须有默认参数
2.函数声明和实现,只能有一个有默认参数
占位参数:返回值类型 函数名(数据类型){} int func(int){}
函数重载
满足条件:同一个作用域下;函数名相同;函数参数类型、个数或者顺序不同
返回值类型不可以作为函数重载的条件!
函数重载避免默认参数

$类和对象
$封装:将属性和行为写在一起,表现事物
struct和class默认访问权限不同
成员属性设置为私有 优点:可以控制读写权限;对于写,可以检测数据有效性
set设置 get显示

构造函数:没有返回值,函数名和类名相同
*分类:
1.按参数分类:有参和无参(默认)构造函数;
2.按类型分类:普通和拷贝构造函数 Person(const Person &p)

*创建:
1.括号法:Person p1/Person p1(10)/Person(p2)
无参构造函数不要加()
2.显示法:Person p2 = Person(10)/Person p3 = Person(p2)
Person(10) 匿名对象 在执行结束后,系统马上回收
不要利用拷贝构造函数初始化匿名对象 Person(p3) 等价于 Person p3
3.隐式转换法:Person p4 = 10 等价于 Person p4 = Person(10)

*调用规则:
1.创建一个类,编译器添加默认构造、拷贝构造、析构函数
2.如果写了有参构造函数,编译器不提供默认构造函数
如果写了拷贝构造函数,编译器不提供其他构造函数
Person()<Person(int age)<Person(const Person&p)

*深拷贝和浅拷贝:
1.浅拷贝:编译器提供,简单拷贝
带来的问题:堆区内存重复释放 height = p.height
2.深拷贝:自己实现,在堆区重新申请空间
解决浅拷贝问题height = new int (*p.height)

*类对象作为类成员:先调用类成员的构造,在调用自身构造
静态成员函数只能访问静态成员变量

*成员变量和成员函数分开存储
空类大小 1个字节
非静态成员变量属于类的对象上

*this指针:指向被调用的成员函数所属的对象
作用:
1.解决名称冲突
2.返回对象本身用 *this
本质:指针常量,不可以修改指针的指向

*常函数和常对象
成员函数后面加const,修饰this指向,让指针的值也不可以修改
const Person *const this == void func() const
加上关键字mutable,在常函数和常对象中可以修改值
常对象(const Person p)只能调用常函数(void func() const)

析构函数:将堆区开辟数据释放

友元
函数:friend void func()可以访问私有内容
类:class B:friend class A 类A可以访问类B私有内容
成员函数:class B : friend void A::func() 类A中func可以访问类B私有内容

运算符重载:operator 自定义数据类型,系统无法判断
*+:
成员函数Person operator+(Person&p) Person p3 = p1+p2
全局函数Person operator+(Person &p1,Person &p2)
*<<
只能利用全局函数重载左移运算符
ostream& operator<<(ostream &cout,Person &p) //ostream输出流类型
友元访问私有成员
*++
前置Person &operator++()
返回引用,可以对同一个数多次操作
后置Person operator++(int) int代表占位参数,区分前置和后置
返回 值,在函数内使用一个局部变量记录初值并返回,局部变量使用完被释放,如果返回引用,非法操作
*=
Person& operator=(Person &p)
先判断是否有属性在堆区,如果有先释放,然后深拷贝,最后返回自身
*==
bool operator==(Person &p)
匿名对象:类型() /Person()

$继承 可以减少重复代码
class 子类:继承方式 父类
子类称为派生类,父类称为基类

*继承方式:公共继承、保护继承、私有继承
父类中私有内容无法继承
公共继承:父类中公共、保护成员到子类中依然是公共(类外可访问)、保护权限
保护继承:父类中公共、保护成员到子类中变为保护权限
私有继承:父类中公共、保护成员到子类中变为私有权限
先调用父类构造函数,在调用子类构造函数;析构函数反过来

*同名继承
1.直接调用为子类成员s.m_A/s.func(),
2.访问父类同名成员,需要加作用域s.Person::m_A/s.Person::func()
3.如果子类中出现和父类中同名的成员函数,编译器会隐藏父类中所有同名函数,如果访问父类中被隐藏的同名函数,需要加作用域

访问静态变量
通过对象访问:s.func()/s.Person::func()
通过类名访问:Son::funr()/Son::Person::func()

*多继承
class 子类:继承方式 父类1,继承方式 父类2。。。
class Son:public Person,public Person2…

*菱形继承:A->B,A->C,B->D,C->D,数据重复,资源浪费
利用虚继承,解决菱形继承问题
class Son:virtual public Person 继承虚基类(最大类A)时加上关键字virtual
vbptr:虚基类指针 指向虚基类表,只有唯一数据

$多态
*静态多态:函数重载,运算符重载,复用函数名 函数地址早绑定

*动态多态:派生类和虚函数实现运行时多态 函数地址晚绑定
满足条件:
1.有继承关系
2.子类重写(函数返回值、声明、参数列表相同)父类虚函数
使用:父类的指针或引用,指向子类对象
Animal &animal = Cat cat / Animal * animal = new Cat

*虚函数:父类 函数前加关键字virtual,子类可加可不加
原理:父类中虚函数会创建vfptr(虚函数指针),将函数入口地址存入虚函数表中,子类继承父类,当子类重写虚函数时,会把继承来的虚函数替换掉,替换为自身的虚函数。当用父类引用或指针指向子类对象时,会从子类虚函数表中找函数入口地址。

*纯虚函数:virtual 返回值类型 函数名 (参数列表) = 0
有了纯虚函数,属于抽象类
特点:无法实例化对象;子类必须重写纯虚函数,否则也属于抽象类

*虚析构:解决父类指针释放子类对象时不干净的问题
父类指针在析构时,不会调用子类析构函数,导致如果子类有堆区属性,会导致内存泄漏

*纯虚析构:需要声明,也需要实现。
virtual ~Animal() = 0; 类外实现Animal::~Animal(){}
有了纯虚析构,也属于抽象类
如果子类中没有堆区数据,可以不写虚析构和纯虚析构

$读写文件
*写文件(文本文件):
1.包含头文件fstream
2.创建流对象 ofstream ofs (fstream 读写)
3.指定打开方式 ofs.open(“文件路径”,打开方式 ios::out)
4.写内容 ofs<<
5.关闭文件 ofs.close()

*读文件:
1.包含头文件fstream
2.创建流对象 ifstream ifs (fstream 读写)
3.打开文件 ifs.open(“文件路径”, ios::in)
并判断是否打开成功 if(! ifs.is_open()) 没有打开成功 return 返回
4.读数据
1.char buf[1024] = {0}; while(ifs>>buf) cout<<buf<<endl;
2.char buf[1024] = {0}; while(ifs.getline(buf,sizeof(buf))) cout<<buf<<endl;逐行输出
3.string buf; while(getline(ifs输出流,buf)) cout<<buf<<endl;
4.char c; while((c = ifs.get()) != EOF文件尾){cout<<c;}逐个字符
5.关闭文件 ifs.close()

*写文件:(二进制方式 字符串不要用string 使用char定义)
class Person{public:char name[20]};
1.包含头文件fstream
2.创建流对象 ofstream ofs (fstream 读写)
3.指定打开方式
ofs.open(“文件路径”,打开方式 ios::out | ios::binary二进制方式)
4.写内容 ofs.write((const char *)&p,sizeof(Person));
5.关闭文件 ofs.close()

*写文件:
class Person{public:char name[20]};
1.包含头文件fstream
2.创建流对象 ifstream ifs (fstream 读写)
3.打开文件 ifs.open(“文件路径”,ios::in | ios::binary)
并判断是否打开成功 if(! ifs.is_open()) 打开失败 return 返回
4.写内容 ifs.read((char *)&p,sizeof(Person));
5.关闭文件 ifs.close()


暂时到这,还有模板之类的没来及学完,后序补上。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值