浙大翁恺c++笔记

01第一个c++程序

02什么是对象

浙大翁恺c++笔记_第1张图片

浙大翁恺c++笔记_第2张图片
通过操作访问数据 数据是被保护起来的 对象其实就是变量 任何变量就是对象
通过外部操作改变data状态 而不是直接接触改变数据
浙大翁恺c++笔记_第3张图片面向过程:事情发生的流程是怎么样,按照时间顺序一步一步会发生什么,即从时间顺序
面向对象:在某个场景中有什么东西,这些东西的关系是什么,比如一间教室里有灯,有学生,有老师等等,他们的关系是怎么样的,即从存在什么样的东西
浙大翁恺c++笔记_第4张图片
浙大翁恺c++笔记_第5张图片
浙大翁恺c++笔记_第6张图片
浙大翁恺c++笔记_第7张图片
设计就是找出思路的过程 实现就是写代码的过程 oo思想关注的是东西是数据而不是过程操作

03面向对象基本原理

浙大翁恺c++笔记_第8张图片
浙大翁恺c++笔记_第9张图片
浙大翁恺c++笔记_第10张图片
object实体 class是种概念不是实体
浙大翁恺c++笔记_第11张图片

oop特点
1万物都是对象实体
2程序就是一堆对象,告诉其他对象根据发送的消息做什么,(每个对象都给其他对象发消息告诉他们做什么而不是怎么做 要不要做)
3每个对象都有自己的内存,对象又是由其他对象组成的
c语言是一堆函数 调来调去回到main函数结束
4 每个对象都有类型 现有类型才有对象
5一个特定类型的所有对象可以接受相同的消息 比如所有水果都能被你咬一口有水喝
可以接受相同消息的对象可以归为同一类

浙大翁恺c++笔记_第12张图片
在这里插入图片描述
浙大翁恺c++笔记_第13张图片
class creator 自己造的类 可以修改类里面的数据 但是client programmers可以调用类但是不能直接接触类中的数据 而是通过接口

浙大翁恺c++笔记_第14张图片

三大特性:封装 继承 多态性

04自动售票机例子

浙大翁恺c++笔记_第15张图片
浙大翁恺c++笔记_第16张图片
浙大翁恺c++笔记_第17张图片
按照过程模拟售票机 不合理 应该关注其内部有什么东西
浙大翁恺c++笔记_第18张图片
浙大翁恺c++笔记_第19张图片

浙大翁恺c++笔记_第20张图片

#ifndef TICKETMACHINE_H_
#define TICKETMACHINE_H_

class TicketMachine
{
private:
const int PRICE;
int balance;
int total;
    /* data */
public:
    TicketMachine();
    virtual ~TicketMachine();
    void showPrompt();
    void insertMoney(int money);
    void printTicket();
    void showBalance();
    void showTotal();
};
#endif

#include "TicketMachine.h"
#include "iostream"
using namespace std;
TicketMachine::TicketMachine():PRICE(10)
{
}
TicketMachine::~TicketMachine()
{
}
void TicketMachine::showPrompt()
{
    cout << "something";
}
void TicketMachine::insertMoney(int money)
{
    balance += money;
}
void TicketMachine::showBalance()
{
    cout << balance;
}
#include "TicketMachine.h"
int main()
{
    TicketMachine tm;
    tm.insertMoney(100);
    tm.showBalance();
    return 0;
} 

浙大翁恺c++笔记_第21张图片

::"类作用域操作符。“::"指明了成员函数所属的类。如:M::f(s)就表示f(s)是类M的成员函数。
::a++ 前面没有类名 表示是全局的
浙大翁恺c++笔记_第22张图片
浙大翁恺c++笔记_第23张图片
浙大翁恺c++笔记_第24张图片
![(https://img-blog.csdnimg.cn/20201028134324929.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1ZW9uZw==,size_16,color_FFFFFF,t_70#pic_center)
浙大翁恺c++笔记_第25张图片img
源代码.c/cpp------>可执行文件.out/exe

预处理生成.i
预处理生成.ii
汇编文件.s
生成二进制.o
链接成可执行文件.out/exe // 多个.o目标文件链接后生成可执行文件

g++ –E main.cpp // 生成.i
g++ –S main.i main.s // 由.i生成.s
g++ -C main.cpp // 生成.o二进制目标文件 .cpp—>.o
g++ main.o -o AA // 由.o目标文件到可执行文件AA.out/exe .o—>.out/exe
g++ main.cpp // 编译连接一起,生成可执行文件a.out/exe .cpp–>.out/exe
g++ main.cpp -o AA // 由.cpp源文件到可执行文件AA.out/exe
浙大翁恺c++笔记_第26张图片
编译程序时 c++只对.cpp进行 只看到一个.cpp文件 看不见其他东西
对头文件 我们只能声明而不能放定义

声明有:extern 变量 函数的原型 class/struct的声明 (只有声明无定义)

int a//定义
extern int a//声明
f()//函数的定义
f// 函数原型即声明
浙大翁恺c++笔记_第27张图片
浙大翁恺c++笔记_第28张图片
自动生成的标准头文件结构 为了防止在一个.cpp文件中 include一个头文件多次而出现那个.h类的声明被重复出现
浙大翁恺c++笔记_第29张图片
一个头文件只放一个类的声明 而其对应的源代码文件用相同的前缀 把后缀改成.cpp 里面放着它所有函数的body(definition) 头文件要用标准头文件给 只能include 声明而不是定义

06时钟例子

抽象 :看待某件事物 有意的看不见一些细节 只会在某个层次看 把进一步的层次屏蔽起来,比如看见一辆车 你就想到大小 颜色 等等 不会去考虑里面座椅皮质是什么材质 轮胎尺寸等等
浙大翁恺c++笔记_第30张图片

浙大翁恺c++笔记_第31张图片
浙大翁恺c++笔记_第32张图片
浙大翁恺c++笔记_第33张图片
浙大翁恺c++笔记_第34张图片

07成员变量

假如在某个函数中定义了一个本地变量 和成员变量的名字相同 c语言就是按照最近原则来 所以本地变量起作用 屏蔽成员变量

浙大翁恺c++笔记_第35张图片

fields成员变量(字段) parameter参数 localvariable本地变量

成员变量值和函数无关 只要对象在他就在
成员变量的作用范围是类的范围 类中的成员函数可以使用这些成员变量
本地变量只能在他的那个函数使用

08成员变量的秘密

声明不告诉这个变量在哪里 只是告诉有这么个东西
类不是实体 只有实体才有变量 如a是实体是对象 才有i这个变量
而函数是属于类的 不是属于对象的 f是A的函数
浙大翁恺c++笔记_第36张图片
浙大翁恺c++笔记_第37张图片
在这里插入图片描述
B中无f函数 只能f(&b)

在这里插入图片描述
浙大翁恺c++笔记_第38张图片
f是类的 i是对象的
cout< 进入a.f() 先输出10 又因为f内i=20 所以输出20
此时输出a.i 变成20 输出20
再申请f(&b) 输出20

浙大翁恺c++笔记_第39张图片

在这里插入图片描述
a的地址和a.i的地址和f()内i的地址一样 所以调用a.i a.f()时地址都是a的 这个联系建立是通过this
浙大翁恺c++笔记_第40张图片
浙大翁恺c++笔记_第41张图片this可以被隐藏的 this是个指针 可以看出f()和this 的地址同
i=20 也可写成this.i
浙大翁恺c++笔记_第42张图片
浙大翁恺c++笔记_第43张图片
浙大翁恺c++笔记_第44张图片

09构造和析构

浙大翁恺c++笔记_第45张图片
浙大翁恺c++笔记_第46张图片
浙大翁恺c++笔记_第47张图片
构造函数(构造器)和类的名字一样而且没有返回类型
这个构造函数会在对象被创建的时候就自动被调用
当你有个对象a时 即X a就会做a.X();

在这里插入图片描述
把对象传给构造函数

浙大翁恺c++笔记_第48张图片
浙大翁恺c++笔记_第49张图片
析构函数 对象结束之前要调用析构函数 析构函数不能有参数 和类名一样 但是前面有~ 析构意味着收回空间
几个对象就是几个析构函数
在这里插入图片描述
浙大翁恺c++笔记_第50张图片
会在before opening brace 之后马上调用构造函数 在构造对象之前
会在after closing brace 之前马上调用析构函数 在结束对象之前

浙大翁恺c++笔记_第51张图片
x1的空间进了f的{}就有 但是因为到了jump1 x1就没有调用构造函数 只有X x1的时候构造才会做 但是跳出{}就会析构x1 但是x1并没构造 所以编译无法通过 会出现问题

10对象初始化

浙大翁恺c++笔记_第52张图片
sizeof c/sizeof *c 求数组c的个数
浙大翁恺c++笔记_第53张图片

缺省 没有参数的构造函数是 default constructior
Y y2[2]={Y(1)} 错误的 因为没给第二个数 相当于告诉编译器去找个default constructior来初始化这个对象 编译器就说 找不到 因为没有

10new和delete

浙大翁恺c++笔记_第54张图片
new 要做:1分配空间2调用构造函数 如int只要分配空间即可 类stash在分配空间完后需要调用构造函数 对象被创建的时候一定会调用构造函数 不论是堆里面的变量还是本地变量 3预算符要有结果 所以返回的是这个空间的地址

new 先分配空间 得到空间再去里面做初始化
delete是先析构 析构完再收回空间

浙大翁恺c++笔记_第55张图片
浙大翁恺c++笔记_第56张图片

delete [] psome是整个数组 不带[]只会调用第一个元素的析构函数 而不是所有元素的
浙大翁恺c++笔记_第57张图片

一张表inchtable 记录这块内存的地址 这个内存有多大

浙大翁恺c++笔记_第58张图片

#include 
using namespace std;
class A
{
private:
    int i;
    int *p;

public:
    A()
    {
        p = 0;
        cout << "A::A()" << endl;
    }
    ~A()
    {
        delete p;
        cout << "A::~A" << i << endl;
    }

public:
    void set(int i) { i = i; }
    void f()
    {
        p = new int;
    }
};
int main()
{
    A *p = new A[10];
    for (int i = 0; i < 10; i++)
    {
        p[i].set(i);
    }
    delete[] p;
    return 0;
}

假设r是数组
其中delete r 表示只调用了第一个元素的析构函数 但是整个r数组的空间都被收回了
delete r[] 会调用每个元素的析构

浙大翁恺c++笔记_第59张图片
注意要new就要delete 虽然在平时作业中进程结束就会终止不会造成影响 进程结束这片内存会被回收 但是如果不是作业就会造成内存泄漏

12访问限制

浙大翁恺c++笔记_第60张图片

oop对象是封装的是被保护的 能接触的只有函数 可以通过函数来要求做什么 但是具体怎么做对数据产生什么影响是代码影响 使用类的程序员(client programmer)不能访问类里面的东西 而对写类的人(Libary designer )可以修改内部的东西而不至于影响别人

浙大翁恺c++笔记_第61张图片
这些权限是指在编译层面的 只在编译时刻检查 是真对类的限制 不是对对象

  • 运行时刻如果有办法的话可以不受限制
    public 任何人可以访问
    private 可以是函数或者变量 只有自己可以访问 即这个类的成员函数可以访问
    protected
    浙大翁恺c++笔记_第62张图片
    浙大翁恺c++笔记_第63张图片
    class vs struct
    class defaults to private
    struct defaults to public

13 初始化列表

浙大翁恺c++笔记_第64张图片
浙大翁恺c++笔记_第65张图片

构造函数的初始化和赋值
赋值做了两件事 先初始化再赋值 只是初始化的时候是用默认的构造器初始化
但是一般编程习惯是在构造函数中初始化

14对象组合 (拿已有对象去拼装新的对象)

三大特性 封装继承多态性

继承是软件重用的回答 或者 继承是实现软件重用的方式
浙大翁恺c++笔记_第66张图片

by reference表示别的对象不是身体本身的一部分 而是其他的 宝宝出生后单独个体 by reference 成员变量是个指针
fully 表示这个对象就是本身的一部分 完全包含 宝宝在肚子里 fully

浙大翁恺c++笔记_第67张图片

浙大翁恺c++笔记_第68张图片
浙大翁恺c++笔记_第69张图片

虽然类saving account里面有类 person和currency 但是初始化和调用函数时不能直接拿这两个类的东西 要通过他们定义的对象 m_saver和m_balance 来调用

15继承

组合是拿对象(object)拼出新的对象 实(对象是实体)
继承是拿类改造一下 造出新的类 虚(类是概念)浙大翁恺c++笔记_第70张图片

浙大翁恺c++笔记_第71张图片
浙大翁恺c++笔记_第72张图片
superset超集 student is a superset of person student是个继承者

浙大翁恺c++笔记_第73张图片
manager is a emploee sub 子类 derived派生类 B继承于A 则有A的任何一切 拥有但是不代表可以直接使用private的东西 只能通过父类的某些函数去使用这些私有成语(比如set print)

#include 
using namespace std;
class A
{
public:
    A(int ii) : i(ii) { cout << "A::A()" << endl; }
    ~A() { cout << "A::~A()" << endl; }
    void print() { cout << "A::print()" << i << endl; }
    void print(int i)
    {
        cout << i;
        print();
    }
    void set(int ii) { i = ii; }

private:
    int i;
};
class B : public A
{
    //若没有public 默认private
    //struct 默认public
public:
    B() : A(15) { cout << "B::B()" << endl; }
    ~B() { cout << "B::~B()" << endl; }
    void print() { cout << "B::print()" << endl; }
    void f()
    {
        set(20);
        //i = 30;
        print();
    }
};
int main()
{
    B b;
    //b.set(10);
    b.print();
    b.f();
    b.print(200);
    return 0;
}

浙大翁恺c++笔记_第74张图片
这里B中 直接令i=30 会报错

浙大翁恺c++笔记_第75张图片
建立某个类时 首先所有数据都是private 要给所有人要用的放在public 留一些protected的接口给子类 告诉子类可以通过protected的东西直接访问一些private的东西 这手段只留给子类 别人不能做

浙大翁恺c++笔记_第76张图片

16父类子类的关系

浙大翁恺c++笔记_第77张图片
浙大翁恺c++笔记_第78张图片
浙大翁恺c++笔记_第79张图片
浙大翁恺c++笔记_第80张图片

加上std::是这个类的全名 因为以前用了using namespace std;
浙大翁恺c++笔记_第81张图片
两个print函数构成重载关系 overload 因为参数不一样

浙大翁恺c++笔记_第82张图片
现在B是A的子类 B中有A的body 所以B要初始化时候,就要遵循A的规则让A自己把自己的那部分初始化 有父类的对象 必须让父类对象初始化 所以父类的构造会被调用

浙大翁恺c++笔记_第83张图片

浙大翁恺c++笔记_第84张图片
如图 B要构造自己的析构函数时候 必须借助A的构造函数 所以先调用A的构造再调用B的 析构是先B后A
浙大翁恺c++笔记_第85张图片
浙大翁恺c++笔记_第86张图片

浙大翁恺c++笔记_第87张图片

父A子B中都有print函数 且A中有重载函数 B中的f也有print函数这个print函数与A中的某个一致(指的是名字参数表一样 )namehidding 名字隐藏 则父类的其他同名函数隐藏了 只有子类自己定义的这个 所以当要调用B.print(20)是不合法的

#include 
using namespace std;
class A
{
public:
    A(int ii) : i(ii) { cout << "A::A()" << endl; }
    ~A() { cout << "A::~A()" << endl; }
    void print() { cout << "A::print()" << i << endl; }
    void print(int i)
    {
        cout << i;
        print();
    }
    void set(int ii) { i = ii; }

private:
    int i;
};
class B : public A
{
    //若没有public 默认private
    //struct 默认public
public:
    B() : A(15) { cout << "B::B()" << endl; }
    ~B() { cout << "B::~B()" << endl; }
    void print() { cout << "B::print()" << endl; }
    void f()
    {
        set(20);
        //i = 30;
        print();
    }
};
int main()
{
    B b;
    //b.set(10);
    b.print();
    b.f();
    b.print(200);
    return 0;
}

17函数重载与默认参数

浙大翁恺c++笔记_第88张图片
函数重载就是 同名 参数列表不同 (类型 个数等等)
浙大翁恺c++笔记_第89张图片

预先给一个值 缺省参数 所以stash 有两种写法 给一个值或给两个值
一定要从最右边省略过来 写在声明里不写在定义里 即可以缺省可以写在.h里面 不可以写在.cpp里面

浙大翁恺c++笔记_第90张图片

default argument是发生在编译时刻 尽量不要使用default value

18内联函数(inline)

overhead 额外的开销
浙大翁恺c++笔记_第91张图片
浙大翁恺c++笔记_第92张图片

内联函数不会像函数调用那样经历push pop等操作 而是相当于会把这段函数代码嵌入这个地方 (在编译的时候这么做) 而仍保持函数的独立性 有函数的空间等等

浙大翁恺c++笔记_第93张图片
浙大翁恺c++笔记_第94张图片
左边是函数调用 右边是内联函数 二者的汇编对比
浙大翁恺c++笔记_第95张图片

inline 必须在声明和定义中都要有。
.cpp是用来产生函数的 .h是给调用这个函数 的地方看的

浙大翁恺c++笔记_第96张图片
浙大翁恺c++笔记_第97张图片
浙大翁恺c++笔记_第98张图片
左边是c的宏 他检查不出double的错误 而inline可以检查出double的错误

浙大翁恺c++笔记_第99张图片
inline不一定会给你插入 如果你有很大的循环或递归的话 编译器就会拒绝

#include 
#include
using namespace std;
class Point
{
    int i, j, k;

public:
    Point() { i = j = k = 0; }
    Point(int ii, int jj, int kk)
    {
        i = ii;
        j = jj;
        k = kk;
    }
    void print(string msg =" " )
    {
        if (msg.size() != 0)
            cout << msg << endl;
        cout << "i = " << i << ", "
             << "j = " << j << ", "
             << "k  = "<< k << endl;
    }
};
int main()
{
    Point p, q(1, 2, 3);
    p.print("value of p");
    p.print("value of q");
    p.print(); 
}

浙大翁恺c++笔记_第100张图片
浙大翁恺c++笔记_第101张图片
类里面的函数body放里面则自动变inline 如point() point(ii jj kk) print都是inline
浙大翁恺c++笔记_第102张图片
所以不会真的调用 只是把代码插到这里来

#include 
using namespace std;
class Cup
{
    int color;

public:
    int getColor() { return color; }
    void setColor(int color)
    {
        color = color;
    }
};

浙大翁恺c++笔记_第103张图片
浙大翁恺c++笔记_第104张图片
浙大翁恺c++笔记_第105张图片
函数的body写在类外 比较清爽

浙大翁恺c++笔记_第106张图片

19 const (保证初始化后不能被修改、赋值)

浙大翁恺c++笔记_第107张图片

浙大翁恺c++笔记_第108张图片
const是变量
浙大翁恺c++笔记_第109张图片

浙大翁恺c++笔记_第110张图片
浙大翁恺c++笔记_第111张图片

const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;所以修改p不可以 指针所指的内容不可以改

const位于*的右侧,则const就是修饰指针本身,即指针本身是常量。q++不可以

星号前是对象是const 写在星号后指针是const
浙大翁恺c++笔记_第112张图片

1 p 即指针所指的内容不能修改
2 对象是const
3p指针不能修改 所以p++不对 p的地址不能改
浙大翁恺c++笔记_第113张图片
int *p 一个普通指针
const int*cip 一个指向const变量的指针 即他所指的变量不能通过他修改的指针
尽管 *cip就是i(因为cip=&i 所以*cip=

&i=i) 但是永远不能写cip=xxx //错误!
cip=&ci 正确 因为保证了 ci不会通过cip这个指针所修改 因为const int

cip 一个指向const变量的指针 即他所指的变量不能通过他修改的指针

#include 
using namespace std;
int main()
{
    //char *s = "hello world";
    char s[] = "hello world ";
    cout << s << endl;
    s[0] = 'B';
    cout << s << endl;
                
    return 0;
}     

浙大翁恺c++笔记_第114张图片
浙大翁恺c++笔记_第115张图片
hello world是常数所以放在代码段内 char*s 实际上是const类型的 所以他不可以被就修改
所以s[0]='B’无效
浙大翁恺c++笔记_第116张图片
在这里插入图片描述

s1在代码里面 与main距离很近 s2在堆栈内
浙大翁恺c++笔记_第117张图片
一个函数f的参数类型是 int* 则无论给他什么类型的int都可以 不管是不是const 所以可以保证对传进来的参数不修改

浙大翁恺c++笔记_第118张图片
表明在f1内不能去改i的值

浙大翁恺c++笔记_第119张图片
值可以赋给非const 的变量 因为并不是要改变他

浙大翁恺c++笔记_第120张图片
通常直接传递一个变量开销很大因为要放堆栈中 所以最好是传地址 但是又不希望所指的内容被修改 所以加const以const身份对象传给你 保证他不被修改 是安全的

浙大翁恺c++笔记_第121张图片

在整个大对象前面加了const 这个对象的值就不能被修改 返回值为常量不能作为左值 整个对象就是const 一旦这么做以后 这个对象的函数就有问题了 因为成员函数可能会修改成员变量
.h只有函数原型 .cpp才有函数body main.c include了.h文件他在编译的时候可以知道整个函数的原型但不知道body 这样就不知道到底哪些成员函数会修改成员变量

一个函数后面有const:在成员函数后面加上const 保证他不去修改任何的成员变量 需要在原型(这样编译器就能检查出来 成员变量是安全的可以用的 )和定义的地方都要加上const
浙大翁恺c++笔记_第122张图片

浙大翁恺c++笔记_第123张图片

20不可修饰的对象

在函数后面写const 即this是const

#include 
using namespace std;
class A
{
    int i;

public:
    A() : i(0) {}
    void f() { cout << "f()" << endl; }
    void f() const
    {
        cout << "f() const" << endl;
    }
};
int main()
{
    const A a;
    a.f();
    return 0;
}

浙大翁恺c++笔记_第124张图片

void f(){...} 等价于 void f(A* this){...} 
void f() const{...} 等价于voide f(const A* this) const{...} 
所以a.f()调用的是第二个函数  因为const A a
二者构成overload的关系 因为实际上他们的参数列表不一样

12345

浙大翁恺c++笔记_第125张图片
浙大翁恺c++笔记_第126张图片

如果成员变量 定义const int i i是const 则i必须在构造函数中初始化 否则会报错 A() {} 不行
必须 A():i(0){}

浙大翁恺c++笔记_第127张图片
const 不能做数组的size

21引用

c++提供了太多可以放对象的地方 1可以放在堆栈里面 2堆里面 3全局数据区里面
提供了太多可以访问对象的方式 1直接掌握一个对象 ,变量里面是对象 2通过指针访问一个对象 3通过引用访问一个对象

浙大翁恺c++笔记_第128张图片
引用时在定义需要给一个初始值 以表明这个r是c的引用 初始值必须是个变量或是一个可以做左值的东西 r就是c的reference r是c的一个别名
浙大翁恺c++笔记_第129张图片
浙大翁恺c++笔记_第130张图片

#include 
using namespace std;
int main()
{
    int x = 47;
    int &y = x;
    cout << y << endl;
    y = 18;
    cout << x << endl;
}

reference的理解 1—y就是x的另一个名字 以后出现y的地方都可以换成x
浙大翁恺c++笔记_第131张图片

引用的初始化会建立一个联系

const int& z=x  z是x的一个别名但是通过z你不能修改x  但是x依然可以改变  
与const int* p=x同  也不能通过p修改x  即不能让z或p做左值
12

引用的目标必须有个位置放他 如i3有结果 但是没有一个有名字的变量(位置 )去放i3这个结果

浙大翁恺c++笔记_第132张图片

浙大翁恺c++笔记_第133张图片

f(int* x){*x)++//x指针所指的内容++
  
}


123456

浙大翁恺c++笔记_第134张图片
因为q是在本地变量 返回q是error return q错误
和用指针返回本地变量的地址一样不正确

x是全局变量可以 return

浙大翁恺c++笔记_第135张图片

#include 
using namespace std;
int *f(int *x)
{
    (*x)++;
    return x;
}
int &g(int &x)
{
    x++;
    return x;
}
int x;
int &H()
{
    int q;
    return x;
}
int main()
{
    int a = 0;
    f(&a);//Ugly(but explicit)
    g(a);//Clean(but hidden)
}
一个函数返回的类型是 &reference 就可以做左值
因为 int& h(){..
}
所以 可以h()=16成立 这使得x=16 因为h()是返回x 且是个reference
1234

浙大翁恺c++笔记_第136张图片
alias 别名

int x;
int &a=x;int &b=a ;错 没有reference的reference

想要b=a
需要
int x,Y;
int &a=x;
int &b=y;
b=a;

reference 两种含义 1一个变量的别名 2实际是种const 指针

浙大翁恺c++笔记_第137张图片

int&* p;//以为是星p的reference的   即p可以取到reference的地址但是实际上reference不能取 


int*& p  //p是reference 所捆绑着变量是个int* 指针

type& rename;
int* & p;
1234567

22向上造型

浙大翁恺c++笔记_第138张图片

把子类的对象当做父类的来看待
比如学生和人 把学生看出人 学生多出来的东西当做不存在
因为指针所指的地址的便宜都是一样的 就算子类有多出来的东西也是在之后加上去的

浙大翁恺c++笔记_第139张图片
upcast一定是正确的 (子类指向父类)downcast有风险 比如你随便找个人不一定就是学生

类型转换和造型的区别:
类型转换 比如double变int 就完全丧失了double的特性
造型 比如学生还是学生 只是我们看待他的眼光变了 不在当他是学生 把他当人看 他的类型没有变所以不是类型转换

浙大翁恺c++笔记_第140张图片
当通过 ep指针输出的print是employee的print 而不是manager的 (不是之前说的那个name hiding)

23多态性

浙大翁恺c++笔记_第141张图片
浙大翁恺c++笔记_第142张图片
circle rectangle ellipses都有共同的成员函数和成员变量

identical 同样的事物 render提供 渲染
浙大翁恺c++笔记_第143张图片
浙大翁恺c++笔记_第144张图片
父类中的virtual 使得子类和父类的同名函数产生了联系 这样后代继承的render也是virtual

浙大翁恺c++笔记_第145张图片

major_axis  minor_axis 长轴短轴
1

浙大翁恺c++笔记_第146张图片

virtual 通过指针或者引用去调用这个函数的时候 去调用render时 不能直接写进来去调用哪个函数 要到运行的时候才能决定 p所指的render是通用的 对任何shape的子类都适用

p是多态的 p指的是谁 就变成谁的动作

浙大翁恺c++笔记_第147张图片

静态绑定 调用的函数在编译的时候就是确定的知道的
动态绑定 在运行的时候才知道调用哪个函数 根据指针所指的对象决定去调哪个函数

浙大翁恺c++笔记_第148张图片

p->render () 因为render是virtual 所以render 可以是ellipse circle的render 所以是动态绑定
但如果是p—>move() move()不是virtual 所以move是shape的

24多态性的实现(virtual)

浙大翁恺c++笔记_第149张图片
浙大翁恺c++笔记_第150张图片

任何类中只要有一个虚函数 只要有一个 他的对象都会比一般的大一点

sizeof(a) 为8 因为是int型
int* p =(int*)&a; //p是变量名 是指针型的(int*型的) 所以传a的地址
p++ 后 *p是10 //*p是指针所指的内容

浙大翁恺c++笔记_第151张图片
有virtual类的对象的的里面 头上会加上一个隐藏的指针叫vttr 他指向一张表叫vtable vtable里面是他所有virtual的函数的地址 vtable是这个类的不是对象的 这个类的所有vttr的值都是一样 浙大翁恺c++笔记_第152张图片
在这里插入图片描述
当使用指针或引用时才会产生动态绑定,通过点去调用不会
浙大翁恺c++笔记_第153张图片

浙大翁恺c++笔记_第154张图片

#include 
using namespace std;
class A
{
public:
    A() : i(10) {}
    virtual void f() { cout << "A::f()" << i << endl; }
    int i;
};
class B : public A
{
public:
    B() : j(20) {}
    virtual void f() { cout << "B::f()" << j << endl; }
    int j;
};
int main()
{
    A a;
    B b;
    A *p = &b;
    p->f();
    return 0;
}
p->f();//调用的是b的f 输出B::f()20
a=b;//因为b是a的子类 所以让b赋值a 合理
但是通过a.f() //输出输出A::f()10 这样调用的是a的f() 虽然f是virtual但是不是通过指针或引用来动态绑定的 所以即使a是由b赋予的 还是调用的A的f



若当
a=b;
p=&a;

p->f();//输出A::f()10 这样调用的是a的f() 因为b只是把值给a 地址并没有传给vttr a的vttr并没有被改变 所以a还是a  所以即使b先赋给a p再取a的地址 a的地址始终是没有变化的

123456789101112

浙大翁恺c++笔记_第155张图片
若如上图 理应输出B::f() 20
但是实际输出的B::f() 32767
浙大翁恺c++笔记_第156张图片
图上写错 应输出B::f()

浙大翁恺c++笔记_第157张图片
因为只是值的传递 所以circ即使赋给elly 调用elly.render 也是ellipse的render 不会是circle 的render 理由同上

浙大翁恺c++笔记_第158张图片
浙大翁恺c++笔记_第159张图片

但如果是指针的话 这样指针的指向改变了 elly就被赋予了circ elly指向circ 所以elly->render() 就是circle的render

浙大翁恺c++笔记_第160张图片
如果是引用的话 耶同理 如果传给func的是circ的话 调用是的circle 的render

如果一个类里面有一个virtual函数 那么他的析构函数必须是virtual 否则会有麻烦

浙大翁恺c++笔记_第161张图片

c++默认是静态绑定 其他op语言默认是动态绑定的 所以c++要加上virtual(为了效率)

浙大翁恺c++笔记_第162张图片

override 覆盖或改写 :父类子类的两个函数名称相同参数表也相同 称为override

浙大翁恺c++笔记_第163张图片

如果需要调用父类的func可以写成 base::func()

在这里插入图片描述

浙大翁恺c++笔记_第164张图片

如上 同样的函数 子类返回了子类的指针 返回了指针的引用可以 但是不能返回对象本身自己 因为只有通过指针或对象才能发生upcasting关系

浙大翁恺c++笔记_第165张图片

如果你在父类有两个virtual的overload的函数 那么你在子类也必须override所有virtutal函数的overload的函数 否则另外的函数会发生namehidding 只有c++这种oop语言存在namehide 其他语言不存在

25引用再研究(const &)

如果一个类的成员是reference 必须使用构造函数的列表初始化
浙大翁恺c++笔记_第166张图片

浙大翁恺c++笔记_第167张图片

引用作为返回值
在一个函数内不能返回本地变量的地址作为指针或reference 必须返回全局变量

浙大翁恺c++笔记_第168张图片

double value=subscript(12)虽然左边是double 右边是reference 看起来类型不匹配 
其实实际上就是把myarray的值赋给value

subscript(3)=34.5 //表面上看是subscript的返回值是34.5  实际上是这个返回值带回的那个变量等于34.5 即myarray[3]=34.5  所以一个函数的返回值的reference是可以做左值的 
1234

浙大翁恺c++笔记_第169张图片

加上const 把这个对象送进函数 保证函数无法通过指针来修改这个对象 但是指针用星号不方便
所以当我们需要穿对象进一个函数的时候 我们用const reference

浙大翁恺c++笔记_第170张图片

如上图y是const reference 不能被修改 不能做左值
1

浙大翁恺c++笔记_第171张图片

func(i*3)func要的是reference 要有具体的变量名 i*3不能做左值
因为i*3 会产生const int reference的临时变量 tmp
但是func接收的是int &类型  而不是const int 
如果func接收的是const int&类型 则func(i*3)可以
因为一个是const int &一个是int &


浙大翁恺c++笔记_第172张图片

26拷贝构造(浅拷贝 深拷贝)

浙大翁恺c++笔记_第173张图片
将currency的对象作为输入

在c++必须分清两种概念 定义和声明 即definition和declaration 还要分清初始化和赋值

currency p=bucks//initialization 
p=bucks//assignment

在声明这个变量的时候 前面有变量类型就是定义  给变量一个值叫initialization
已经定义好变量了 你再给他值叫assignment 
    
#include 
#include
using namespace std;


static int objectCount=0;
class howmany{
	public:
		howmany(){objectCount++;print("hommany()");}
	// howmany(int i){objectCount++;print("hommany(int)");}
	//如果在定义一个带int的构造函数时,之后在main里面
	//howmany h2=10;和howmany h2(10)就是等价的 输出的结果完全一样
		void print(const string& msg=""){
		    if(msg.size()!=0) cout<

howmany这个类会对构造和析构函数调用的次数维持一个计数

howmany这个函数 完全对象传入 对象传出 (对象返回)

浙大翁恺c++笔记_第174张图片
拷贝构造

注意这里是member variable的拷贝 不是字节对字节的拷贝 是成员级别上的拷贝

浙大翁恺c++笔记_第175张图片
如果有指针的拷贝指针即两个指针指向同一片内存单元

27拷贝构造二

浙大翁恺c++笔记_第176张图片
浙大翁恺c++笔记_第177张图片
左边的拷贝构造会出现问题 如下 所以我们希望实现的拷贝构造是右边这样的

浙大翁恺c++笔记_第178张图片
浙大翁恺c++笔记_第179张图片
输出结果是p1 p2的名字相同
在这里插入图片描述

输出的结果是p1p2的名字地址相同 即p1p2指向同一片内存 同时还有一个malloc错误 因为p1p2指向同一片内存 又free两次因为p1p2都要析构 所以报错

浙大翁恺c++笔记_第180张图片
浙大翁恺c++笔记_第181张图片
private是针对类而不是对象 所以去访问同类对象的private的东西是完全ok的

浙大翁恺c++笔记_第182张图片

浙大翁恺c++笔记_第183张图片

什么时候拷贝构造会发生?
隐含场景 1调用一个函数时 函数参数是对象本身(不是指针也不是引用) 就意味调用这个函数的时候 我要重新去创建一个新的person类的对象 这时候就会发生拷贝构造 因为我要用某个对象去初始化这个player
明显场景 person p1=p2

浙大翁恺c++笔记_第184张图片

baby_b和baby_c用baby_a构造 等号和括号是一样的 都是初始化 这是明显的拷贝构造的场景

Person baby_c(baby_a)//这是初始化

浙大翁恺c++笔记_第185张图片

浙大翁恺c++笔记_第186张图片

Person p=f()
{  
  Person ip;
  return ip;
  

}


int main(){
    Person p=f()//拷贝构造 一定会有新的对象构造出来 因为f返回的是一个person 的对象 
    //可能会发生两种情况 1 Person p=ip  2 Person@tmp=f(); Person p=@tmp;
    return 0;
    
 }
123456789101112131415

浙大翁恺c++笔记_第187张图片
编译器会把不必要的拷贝优化出去 optimaze·out

浙大翁恺c++笔记_第188张图片
其实本质就是拿who 构造外面这个对象 所以在第二种方法中就会一步到位优化成无需拷贝构造

浙大翁恺c++笔记_第189张图片
任何对象只能被初始化一次 做完之后再对它做其他动作就是assiment assiment可以多次

person p=p1//initialization
p1=p2//assiment

浙大翁恺c++笔记_第190张图片
用string 可以不用拷贝构造 以为string实际上就是一个类

c++尽量用string而不是char*

浙大翁恺c++笔记_第191张图片

copy ctor :拷贝构造

建议 :一旦写了一个类就必须给他三个函数default constructor ;virtual constructor ;copy constructor

28静态对象

浙大翁恺c++笔记_第192张图片
static 1 持久存储(在哪) 2访问收局限(谁能看见你)

c中static的本地变量就是全局变量 因为持久存储
一个全局变量是static 这个全局变量就只在.c文件里面有效

浙大翁恺c++笔记_第193张图片
deprecated 过时的
static local variables 持久存储
static 成员变量 在所有对象内共享
static 成员函数 在所有对象内共享只能访问静态对象和函数

int g_global 全局变量可以通过extern在另一个单元访问 如在 file2
static int s_global 只能file1使用 即使使用extern也不可以
static void hidden 在file2也不能被访问

就算编译阶段可以通过 但是了link阶段无法通过

浙大翁恺c++笔记_第194张图片

浙大翁恺c++笔记_第195张图片
浙大翁恺c++笔记_第196张图片
浙大翁恺c++笔记_第197张图片

浙大翁恺c++笔记_第198张图片

浙大翁恺c++笔记_第199张图片
浙大翁恺c++笔记_第200张图片

空间在全局数据区 编译或链接的时候分配空间
全局变量的构造函数的执行什么时候做:程序一运行的时候但是在main函数之前
所以main就不是我们第一个被调用的函数了 真正程序跑的第一条代码根本不是main函数
只是程序员所以能看见的所能写的第一条代码时main函数
程序要结束的时候 对应的析构会执行

浙大翁恺c++笔记_第201张图片
如果一个程序有多个点cpp文件 每个文件都会有一个全局变量
每个文件都有全局变量 这些全局变量谁先初始化谁后初始化 是没有规定规矩的 设置同一个编译器这次编译和下次编译都不一样 这样有依赖的全局变量不能被保证初始化顺序(依赖指的是某个变量要由另一个变量初始化 )

所以把有依赖的全局变量放在一个文件里

29静态成员

浙大翁恺c++笔记_第202张图片

persistent:全局的(含有静态的本地) malloc的东西
在c++里面static不实现hidden 只实现persistent 在一个类中一个变量不会因为对象的不同而改变 即不依赖对象 所以static member 是class-wide 整个类的东西

浙大翁恺c++笔记_第203张图片

浙大翁恺c++笔记_第204张图片
若写成static int i会编译错误显示找不到i
若去掉static编译通过 输出b.print()的结果0 因为没有找到i

静态的成员变量实际在全局 但是写在class内的都是declaration不是definition
在这里插入图片描述
如写extern int i是声明不是定义 只是告诉编译器某个地方有个叫i的东西 但是我不知在哪里 到时候link会帮我找出来

所以如果你在class写了某个static 的成员变量 相当于extern 的效果 所以应该在.cpp内加int A::i否则只是声明 没有定义 不能是static int A::i 因为类的静态成员可能在外部被访问 不是只在点cpp被访问

浙大翁恺c++笔记_第205张图片
如图 这样输出结果是10 因为静态的成员变量实际上是全局的 只有那一个 所以b.pritnt就是被a改变的那个i

#include 
using namespace std;
class A
{
public:
    A() { i = 0; }
    void print() { cout << i << endl; }
    void set(int ii) { i = ii; }
    static void say(int ii) { cout << ii << " " << i << endl; }

private:
    static int i;
};
int A::i;
int main()
{
    A a, b;
    a.set(10);
    b.print();

    a.say(0);
    A::say(0);
    return 0;
}

浙大翁恺c++笔记_第206张图片

在这里插入图片描述报错 因为

initialization只能对非静态的成员初始化 不能对静态成员初始化

所以 A():i(0){} 不行 静态成员只能在定义的地方被初始化 即int A::i=20;

浙大翁恺c++笔记_第207张图片
即使A::i是全局的 到那时还是不能直接cout A::i 还是会报错在这里插入图片描述

c++内所有函数都是全局的
调用静态函数的方法 没有建立这个类的对象之前也可以访问调用这个函数

 A a;
 a.say(0);
 A::say(0);
123

浙大翁恺c++笔记_第208张图片
在这里插入图片描述
报错 静态的函数只能调用静态的成员变量 因为静态的成员函数是没有this的 因为this表达的是调用这个函数的那个对象 this是个hidden private 因为可以通过A::say()调用,里面没有一个对象 所以会报错

在这里插入图片描述
改成this->i 也不行 虽然i是静态的
在这里插入图片描述
因为this表达的是调用这个函数的那个对象 this是个hidden private 因为可以通过A::say()调用 所以这里面没有一个对象 所以会报错

30运算符重载基本规则(copy assignment operator)

浙大翁恺c++笔记_第209张图片
浙大翁恺c++笔记_第210张图片
在C语言中,多个表达式可以用逗号分开,其中用逗号分开的表达式的值分别结算,但整个表达式的值是最后一个表达式的值。
假设b=2,c=7,d=5,
a1=(++b,c–,d+3);
a2=++b,c–,d+3;
对于第一行代码,有三个表达式,用逗号分开,所以最终的值应该是最后一个表达式的值,也就是d+3,为8,所以a1=8。
对于第二行代码,那么也是有三个表达式,这时的三个表达式为a2=++b、c–、d+3,(这是因为 赋值运算符比逗号运算符优先级高)所以最终表达式的值虽然也为8,但a2=3。

浙大翁恺c++笔记_第211张图片
浙大翁恺c++笔记_第212张图片

浙大翁恺c++笔记_第213张图片
浙大翁恺c++笔记_第214张图片
如果是成员函数的话 this是他的第一个参数 这是隐藏默认的
所以+再给一个that变量即可

浙大翁恺c++笔记_第215张图片

浙大翁恺c++笔记_第216张图片

x+y//编译器发现加号左边是个interger 所以运算符左边的算子叫做receiver
这个加可能有Interger加 float加 所以取决于左边的receiver的类型来觉得怎么加
因为x是interger 所以就是interger加

z=x+y//用的overload的加
z=x+3//x是integer加 所以会把3这个int型的数变interger 再来加
z=3+y//3是int 所以用整数的加来加 y是interger 所以他需要interger这个类有个手段把interger变成int 但是interger没有 所以编译不通过

浙大翁恺c++笔记_第217张图片
浙大翁恺c++笔记_第218张图片

如果作为全局函数 而不是成员函数 就需要把左边右边的两个算子写上去

浙大翁恺c++笔记_第219张图片
两个参数上都可以做类型转换
浙大翁恺c++笔记_第220张图片

浙大翁恺c++笔记_第221张图片
以上转换都可以 z=3+y//在全局函数内可以 因为当他发现用3 int加没法做的时候 就会把3变成interger来做 因为全局函数两个参数上都可以做类型转换 而成员函数要根据左边算子的类型来加 且看右边算子能不能自动变成左边算子的类如 z=3+3.5 不行因为float不能自动转变成int 必须强制类型转换 (int) z=3.5+3 可以 因为int可以自动变float

浙大翁恺c++笔记_第222张图片
单目的 以及= ()[] -> ->* 31
做成成员函数
所有其他的二元运算符做成非成员的

31运算符重载-原型

浙大翁恺c++笔记_第223张图片
对于参数传递
1传进去一定是引用
2若运算符会修改算子 就不能传const进去 不会修改算子的必须传const
+= -= boolean 会修改算子

3如果是成员函数 this是加在后面的const 全局函数一个加或者两个都加

浙大翁恺c++笔记_第224张图片

返回值取决于你是对自己做了修改还是 制作了一个新的对象 制造出来的新对象是不是可以继续做左值

比如加法就是制造一个新的东西来 a+b=6不可以 所以他一定是const的对象
赋值来说a=6 实际上是修改了自己 所以函数后面不能有const 返回的就是reference 还可以做左值

浙大翁恺c++笔记_第225张图片

++a 返回的是当时的结果 所以返回的是对象 返回a的reference 且前面有const 防止++a做左值
a++=6是不行的

a++ 要返回的是a以前的结果 而a++执行后已经不是a以前的那个结果了

浙大翁恺c++笔记_第226张图片

Integer old(*this)//拷贝构造 用一个对象制造一个新的对象 ++a的调用
++(*this)//第一个++函数定义第二个++函数 第一个加加是++a的调用 第二个加加是a++的调用

浙大翁恺c++笔记_第227张图片

浙大翁恺c++笔记_第228张图片
关系运算符 默认this是左算子

浙大翁恺c++笔记_第229张图片

浙大翁恺c++笔记_第230张图片

浙大翁恺c++笔记_第231张图片
浙大翁恺c++笔记_第232张图片

32运算符重载 赋值

浙大翁恺c++笔记_第233张图片
第一行调用拷贝构造函数
第二行调用赋值函数 如果你没对赋值函数重载 就调用系统默认的

#include 
using namespace std;
class Fi
{
public:
    Fi()
    {
    }
};
class Fee
{
public:
    Fee(int) {}
    Fee(const Fi &) {}
};
int main()
{
    Fee fee = 1; //Fee(int)
    Fi fi;
    Fee fum = fi; //Fee(Fi)
    fum = fi;
}

浙大翁恺c++笔记_第234张图片
Fee fee=1//Fee(int)
Fi fi //default constructor 构造出来
Fee fum=fi//Fee(Fi)
fum=fi

浙大翁恺c++笔记_第235张图片系统给你的=是memberwise 而不是bitwise
浙大翁恺c++笔记_第236张图片
自己构造赋值函数时候 应该是个成员函数 对自己做赋值然后返回自己

浙大翁恺c++笔记_第237张图片
如果自己不等于那个that 做赋值
如果自己就是那个that 就不做赋值
什么情况下拿自己等了一遍自己是有坏处的 ?如下图

浙大翁恺c++笔记_第238张图片

如果此时that就是this delete p后p和that是同个东西 that.p不存在 不指向原来那片空间
所以strcpy(p,that.p)无法实现

所以重载=时 一定要有this!=rhs的判断
浙大翁恺c++笔记_第239张图片

赋值重载 如果类里面有动态分配内存的话写,如果里面没有动态分配内存没有指针全都是成员对象 可以不写 可以用系统的
如果想防止系统做的行为不正确 可以声明为private 但是代价很大 相当于这个类的对象不能被赋值

33运算符重载—类型转换

我们希望一些类的作用是用来表达一些值的
value class:看起来像基本元素类型 被函数传进来传出去 运算符需要被重载(如分数 的加法乘法) 这个通常可以被转化为其他类型

浙大翁恺c++笔记_第240张图片

string abc("abc")
PathName  xyz(abc)// 简单构造函数的调用 ok
xyz=abc //
OK 先把abc用构造函数先做成一个pathname  
然后pathname和xyz做一个 operator assiment 
(这里是default assiment 因为成员是另外一个对象不是指针 ) 
他会递归的调用string的perator assiment  所以做两个string类的assiment是ok的
1234567
#include 
using namespace std;
class One
{
public:
    One() {}
};
class Two
{
public:
    Two(const One &) {}
};
void f(Two) {}
int main()
{
    One one;
    f(one); //Wants a Two ,has a One
}

浙大翁恺c++笔记_第241张图片

f想要一个two 确给了一个one 所以编译器会先用这个one去调用two的构造函数 构造一个two给f 所以是可以发生的

浙大翁恺c++笔记_第242张图片

explicit 显示的 告诉编译器我这个构造函数只能做构造函数 不能自动类型转化

浙大翁恺c++笔记_第243张图片

f(Two(one)) 用two的构造函数构造一个新的two的对象出来 然后交给f

浙大翁恺c++笔记_第244张图片

一个A类里面的operator double()是用来把A类的对象变成double的

浙大翁恺c++笔记_第245张图片

以下为自动转换 从窄的到宽的 会自动转 (即左边类型的变量可以赋给右边类型的变量)
浙大翁恺c++笔记_第246张图片
T给T& 初始化时是绑定 赋值时是operator assiment
T&给T 就是赋值
T给void viod*就是个指针但是不特定指向任何东西 我原来那那块东西当T看 但是变成void的我就不拿他当任何东西来看 但是那块东西本身没有变化

T的对象可以变C的对象的情况
1 C类有个构造函数 他拿T可以做出新的对象 就可以把T转成C
2 T类定义了一个operator C()

但是当以上两者都可以时 若没有在构造函数前面加explicit时让其不能自动转换 这样就会报错 因为编译器不知道该用哪一个转化 如下图

浙大翁恺c++笔记_第247张图片

所以解决办法是 浙大翁恺c++笔记_第248张图片
在Orange(Apple)前加explicit

#include 
using namespace std;

class Orange;
class Apple
{
public:
    operator Orange() const; //Convert Apple to Orange
};
class Orange
{
public:
    explicit Orange(Apple) //Convert Apple to Orange
};
void f(Orange) {}

int main()
{
    Appple a;
}

要不要用类型转换函数呢 一般来说 不要用 因为自动做的事情你一般不知道
浙大翁恺c++笔记_第249张图片

34模板一

浙大翁恺c++笔记_第250张图片
浙大翁恺c++笔记_第251张图片

把他做成函数模板 不是模板函数(sort 等等可以处理int float等等类型的排序) 模板函数(重点是函数)是函数模板(重点是模板)的实例

浙大翁恺c++笔记_第252张图片

浙大翁恺c++笔记_第253张图片
模板就是规定我要做一个这样的函数 怎么做 相当于告诉编译器 编译器会帮你做
模板其实是declaration 不是definition

浙大翁恺c++笔记_第254张图片用了模板就不用类型转换

浙大翁恺c++笔记_第255张图片
浙大翁恺c++笔记_第256张图片
浙大翁恺c++笔记_第257张图片
浙大翁恺c++笔记_第258张图片

把int变成complex只有一种方法 如果complex的构造函数是用int作为输入的 且不是explicit

vector的函数每一个都是函数模板 类模板的每一个函数都是函数模板 所以要记得加

浙大翁恺c++笔记_第259张图片

浙大翁恺c++笔记_第260张图片

arr是T类型的 遇见swap的时候 是交换T类型的 但是编译器并不会在这是造出T类型的交换 这里只是声明不是定义
并且在arr[j] 所以说sort用了operator<

浙大翁恺c++笔记_第261张图片

浙大翁恺c++笔记_第262张图片

Vector > > >// 有个vector每个单元都是vector vector每个单元都是一个double的指针 小心两个大于号连起来 会被识别成右移符号 所以需要有空格
Vector
一个vector里面的成员是函数指针(看<>部分) 返回的是int 他的参数表是两项 1是引用 2是int

浙大翁恺c++笔记_第263张图片
在这里插入图片描述
不是模板的继承 而是模板中出现了继承的东西

36异常基本概念

浙大翁恺c++笔记_第264张图片

浙大翁恺c++笔记_第265张图片
读个文件的五个步骤可能会出现各种各样的问题 每一步都可能存在问题和危机

判断每一步是否会异常的动作
浙大翁恺c++笔记_第266张图片
try就是尝试的五个步骤 如果捕捉到某个步骤异常 就做xxx浙大翁恺c++笔记_第267张图片
浙大翁恺c++笔记_第268张图片
浙大翁恺c++笔记_第269张图片
exception的好处是把业务逻辑和错误处理分的很清楚
如try 五句话 catch五部分

37异常的抛出和捕捉

浙大翁恺c++笔记_第270张图片
浙大翁恺c++笔记_第271张图片
浙大翁恺c++笔记_第272张图片
浙大翁恺c++笔记_第273张图片

如果越界的话 怎么办
1 返回一个随机的内存对象 不能接受 因为你可能会写到别人的内存地址上
2返回一个特殊的错误值 表达这是一个错误 不是好办法 因为错误值可能与后续的操作数相加减
3 exit 退出吧
4 assert 但是也不合适 因为assert表达的是代码的错误
所以综上用exception
浙大翁恺c++笔记_第274张图片
在这里插入图片描述
浙大翁恺c++笔记_第275张图片
浙大翁恺c++笔记_第276张图片
所以一般扔出的是一个类里面的对象
在堆里:有且仅有new出来的东西
全局数据区里:全局变量 静态本地变量 静态成员变量
在堆栈里:本地变量 函数内部产生的对象

index这个对象在堆栈里 因为他是函数内部的变量

浙大翁恺c++笔记_第277张图片
先看throw所在的大括号是什么 发现是if语句 所以if之后的语句不会被执行

int i=v[42] 相当于throw 然后带着这个对象离开这个函数

浙大翁恺c++笔记_第278张图片
一般异常发生了往下走 不会再回去了

浙大翁恺c++笔记_第279张图片
catch里面有throw可能是因为处理的层级不够 我可能可以做些小调整但是还需要更高的层次来帮忙

浙大翁恺c++笔记_第280张图片
… 代表万能捕捉器 表示所有异常

浙大翁恺c++笔记_第281张图片
一旦有异常发现就会沿着调用的链条一直找到try和匹配catch 的地方 然后事情在那里得到处理

exception常用于输入输出

浙大翁恺c++笔记_第282张图片
如果发生问题用throw 这个语句产生异常 这个控制就会回到能控制处理这个异常的第一个部分 回去是随着调用的链和堆栈回去的 堆栈内的东西被catch后最终会被恰当的销毁

38异常语句

浙大翁恺c++笔记_第283张图片
浙大翁恺c++笔记_第284张图片
… 是代表所有的异常 但是拿不到对象 最好不要用
浙大翁恺c++笔记_第285张图片
在所有catch里面先做1 在做2 在做3
或者针对每一条catch 做1 2 3
浙大翁恺c++笔记_第286张图片
浙大翁恺c++笔记_第287张图片
先看第一个catch里面是不是exact 不是
然后能不能符合base device conversion 不符合
最后是不是ellipses 不是
所以看第二个match
是不是exact 不是
然后能不能符合base device conversion 符合 所以走这个

每一个catch都按顺序按照那三个原则看能不能被匹配

在这里插入图片描述

void abc(int a):throw(MathErr){
... //告诉别的程序说 运行时刻最多只会抛出圆括号里面的那些类的异常 异常可能发生不是一定发生 发生了也只会出现()内的异常  这是限制abc
}
123

浙大翁恺c++笔记_第288张图片
浙大翁恺c++笔记_第289张图片
c中用malloc分内存,不够是会返回null c++用new分内存 不够会返回bad_alloc()的异常

浙大翁恺c++笔记_第290张图片
浙大翁恺c++笔记_第291张图片
浙大翁恺c++笔记_第292张图片

构造函数出错了 抛异常 这样这个对象构造没有完成 析构是不会被调用的 如果在构造函数抛异常 别人无法拿到这个对象

new是先分配内存 先有内存然后执行构造函数 吧这个内存地址交给构造函数 于是构造函数去构造他

但是构造函数抛了异常 构造无法形成 所以p不存在 p不知道在哪 所以这是内存垃圾

所以解决办法:在构造函数加上 delete this
浙大翁恺c++笔记_第293张图片

浙大翁恺c++笔记_第294张图片
浙大翁恺c++笔记_第295张图片
如果是new出来的 *p 一定要记得delete p

浙大翁恺c++笔记_第296张图片
我们倾向于抛的是堆栈里的对象

39流的概念

浙大翁恺c++笔记_第297张图片
文件二进制和文本文件

浙大翁恺c++笔记_第298张图片
inserters 把一个对象插入到一个输出流的运算符<<
extractors >>把一个对象插入到一个输入流的运算符

浙大翁恺c++笔记_第299张图片

流是一维单方向和文件不一样 文件可以在里面任意流动可以在任意地方读和写

浙大翁恺c++笔记_第300张图片
浙大翁恺c++笔记_第301张图片
在这里插入图片描述
scanf printf cin cout都是对文本文件操作的 所有的输入输出都是在做解析
二进制字符转换成了我们看见的ASCII码 这叫parse 解析
文本文件都要经过 输入其实是解析 输出其实是格式化

二进制文件 人是看不懂的 是直接对其读和写

40流的运算符

浙大翁恺c++笔记_第302张图片
浙大翁恺c++笔记_第303张图片
浙大翁恺c++笔记_第304张图片
浙大翁恺c++笔记_第305张图片
自定义的>> 返回的要是 isream&
浙大翁恺c++笔记_第306张图片
浙大翁恺c++笔记_第307张图片
浙大翁恺c++笔记_第308张图片
浙大翁恺c++笔记_第309张图片
在这里插入图片描述
浙大翁恺c++笔记_第310张图片

规定输出的格式 endl是manipulators
浙大翁恺c++笔记_第311张图片
浙大翁恺c++笔记_第312张图片
浙大翁恺c++笔记_第313张图片
set是变为1 reset是变为0

浙大翁恺c++笔记_第314张图片
浙大翁恺c++笔记_第315张图片
浙大翁恺c++笔记_第316张图片

41stl简述

浙大翁恺c++笔记_第317张图片
浙大翁恺c++笔记_第318张图片
浙大翁恺c++笔记_第319张图片
sets 集合没有重复的是无序的 maps映射

浙大翁恺c++笔记_第320张图片

浙大翁恺c++笔记_第321张图片

#include 
#include 
using namespace std;
int main()
{
    vector x;
    for (int a = 0; a < 1000; a++)
    {
        x.push_back(a);
    }
    vector::iterator p;
    for (p = x.begin(); p < x.end(); p++)
    {
        cout << *p << " ";
    }
    return 0;
}

浙大翁恺c++笔记_第322张图片
浙大翁恺c++笔记_第323张图片
v.swap(v2)交换的是两个vector的值
浙大翁恺c++笔记_第324张图片
浙大翁恺c++笔记_第325张图片
浙大翁恺c++笔记_第326张图片

你可能感兴趣的:(c++基础,c++,开发语言,后端)