C++语法知识复习2(黑马程序员教程P109-p146)

C++学习


1、类和对象

P109 析构函数调用规则

在这里插入图片描述

因为默认构造函数对其属性进行了拷贝

在这里插入图片描述
在这里插入图片描述


p110 深拷贝与浅拷贝

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。

复制(拷贝)构造函数,形参必须是本类对象的引用。若类中没有定义复制构造函数,系统会定义一个默认的复制构造函数,完成将一个对象的所有数据成员复制(拷贝)到另一个对象的相应数据成员中。也就是浅拷贝。


深拷贝与浅拷贝
在这里插入图片描述

浅拷贝:编译器做的简单赋值操作叫做浅拷贝

在这里插入图片描述

堆区开辟的数据由程序员手动开辟,也需要程序员手动释放
test01() 执行完 对象p1p2就被销毁了
在对象p1p2销毁前需要将堆区数据释放,p1p2对象销毁前会调用 析构函数
因此可以使用析构函数释放堆区数据

在这里插入图片描述

在这里插入图片描述

因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
因为p1p2是局部变量(对象),所以在栈上,栈上的规则就是先进后出
在这里插入图片描述
所以对象p2先被释放,先执行p2的析构函数

编译的会出现问题,出现问题的原因如下::

在这里插入图片描述


tips:vscode可能对于这个例子不会蹦


在这里插入图片描述

存放的数据一样,但是指针指向的内存不一样
重新在堆区找块内存存放,也就是说存放的内容(160)一样,但是内存也就是地址不一样
这就叫深拷贝


自定义编写拷贝构造函数,完成深拷贝。
自定义编写拷贝构造函数,完成深拷贝。
自定义编写拷贝构造函数,完成深拷贝。
自定义编写拷贝构造函数,完成深拷贝。
自定义编写拷贝构造函数,完成深拷贝。


在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;

class Person
{
    public:
        //无参(默认)构造函数
        Person()
        {
            cout << "无参构造函数,也就是默认构造函数" << endl;
        }
        //有参构造函数
        Person(int age,int height)
        {
            m_Age = age;
            m_Height = new int(height);
            cout << "有参构造函数" << endl;
        }

        //拷贝构造函数  深拷贝解决浅拷贝的问题
        Person(const Person &p)
        {
            cout << "Person的拷贝构造函数使用" << endl;
            m_Age = p.m_Age;
            m_Height = new int(*p.m_Height);//深拷贝解决浅拷贝的问题
        }


        //析构函数
        ~Person()
        {
            //析构代码,将堆区开辟的数据做释放操作
            if(m_Height != NULL)
            {
                delete m_Height;
                m_Height = NULL;
                cout << "Person的析构函数调用" << endl;
            }
        }

            
            
        
        int m_Age;
        int *m_Height;
};

void test01()
{
    Person p1(10, 160);
    cout << p1.m_Age << "\t" << *p1.m_Height << endl;
    Person p2(p1);
    cout << p2.m_Age << "\t" << *p2.m_Height << endl;

}

int main()
{
    test01();
    return 0;
}

这样的话,析构的时候,各自释放各自的堆区内存,因为内存不一样了。所以肯定不会出现重复释放内存(也就是地址)的问题

在这里插入图片描述
浅拷贝是编译器根据默认拷贝构造函数自动完成的
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


p111 初始化列表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;


class Person
{
    public:
        // //传统的初始化方式
        // //也就是有参构造函数
        // Person(int a, int b, int c)
        // {
        //     m_a = a;
        //     m_b = b;
        //     m_c = c;
        // }

        // //初始化列表进行初始化属性
        // Person() : m_a(20), m_b(2574), m_c(199)
        // {

        // }


        //更加灵活 初始化列表进行初始化属性
        Person(int a, int b, int c) : m_a(a), m_b(b), m_c(c)
        {

        }

        int m_a;
        int m_b;
        int m_c;
};


void test01()
{
    Person p1(3,2,41);
    cout << p1.m_a << "\t" << p1.m_b << "\t" << p1.m_c << endl;
}


int main()
{
    test01();

    return 0;
}

p112 类对象作为类成员

在这里插入图片描述

A是类(也就是自定义的数据类型)
a是对象成员,数据类型为A

在这里插入图片描述

对象成员也可以使用初始化列表的方式进行初始化,可能会使用到构造函数调用中的 隐世转换法

#include <iostream>

using namespace std;
#include <string>

//手机类
class Phone
{
    public:
        Phone(string name) :m_pName(name)
        {
            cout << "手机类构造函数的调用" << endl;
        }


        ~Phone()
        {
            cout << "Phone的析构函数" << endl;
        }

        string m_pName;
};

//人类
class Person
{
    public:
        //后面那个初始化相当于Phone m_phone = pname  也就是隐世转换调用
        Person(string name, string pname) :m_name(name), m_phone(pname)
        {
            cout << "人类构造函数的调用" << endl;
        }

        ~Person()
        {
            cout << "Person的析构函数" << endl;
        }
        //姓名
        string m_name;
        //手机
        Phone m_phone;
};


void test01()
{
    Person p1("张帅", "华为");
    cout << p1.m_name << "使用" << p1.m_phone.m_pName << endl;
}

int main()
{
    test01();
    return 0;
}

当其他类对象作为本类成员时,构造时先构造其他类对象,再构造本类对象,析构的顺序与构造的顺序相反

p113 静态成员

在这里插入图片描述

1、所有对象共享一份数据,对象a的这个数据变化后,对象b调用这个数据时也变化了。
2、在编译阶段分配内存:也就是指:程序还没有运行之前,(程序编译后,)生成exe还没有双击之前就已经分配好内存了,放在全局区里面

静态成员变量,不属于某个对象上,所有的对象都共享同一份数据
静态成员变量,不属于某个对象上,所有的对象都共享同一份数据
静态成员变量,不属于某个对象上,所有的对象都共享同一份数据
教程连接

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;
#include <string>


class Person
{
    public:
        static int m_a;
};

int Person::m_a = 10;


void test01()
{
    Person p1;
    cout << p1.m_a << endl;

    Person p2;
    p2.m_a = 200;
    cout << p1.m_a << endl;

}



void test02()
{
    //1、通过对象进行访问
    Person p3;
    cout << p3.m_a << endl;
    //2、通过类名进行访问
    cout << Person::m_a << endl;
}
int main()
{
    test02();

    return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

p114 成员变量与成员函数分开存储

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

p115 this指针(没太听懂¥¥¥¥¥¥¥)

在这里插入图片描述

this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象
this指针指向 被调用的成员函数所属的对象

1、解决名称冲突
在这里插入图片描述
2、返回对象本身用*this

在这里插入图片描述

按引用返回,返回是对象本身。。。按值方式返回,返回的不是对象本体,而是调用拷贝(负责)构造函数新建的一个对象,见复习1文档的最后内容

按引用返回,返回是对象本身。。。按值方式返回,返回的不是对象本体,而是调用拷贝(负责)构造函数新建的一个对象,见复习1文档的最后内容

按引用返回,返回是对象本身。。。按值方式返回,返回的不是对象本体,而是调用拷贝(负责)构造函数新建的一个对象,见复习1文档的最后内容

我明白了
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
之所以用引用返回的方式,是因为叠加是在原数据(也就是p2)改变的基础上递增,所以用引用。


如果去掉引用返回,也就是去掉&后,每一次调用都会返回一个新的对象(因为值方式返回的原因,每一次调用后返回的都是一个新的对象,调用了拷贝构造函数,最后也就不是p2了,而是p2\\)


如下:
在这里插入图片描述
所以最后输出的时候,p2.age只加了一次而不是三次。

总结:此例子中,如果值方式返回则:会创建新的对象。如果引用方式返回,则:不会创建新的对象,一直都是p2。


有了*this 就可以使用连式编程思想进行编程
有了*this 就可以使用连式编程思想进行编程
有了*this 就可以使用连式编程思想进行编程
有了*this 就可以使用连式编程思想进行编程

在这里插入图片描述

#include <iostream>

using namespace std;



class Person
{
    public:
        Person(int age)
        {
            cout << "有参构造函数" << endl;
            //**this指针指向 被调用的成员函数所属的对象**  
            //解决名称冲突 this指针的作用之一
            this->age = age;
        }
        
        //引用的方式返回
        Person & PersonAddage(Person &p)
        {
            this->age += p.age;
            return *this;
        }
        ~Person()
        {
            cout << "析构函数" << endl;
        }

        int age;
};


void test01()
{
    Person p1(10);
    Person p2(25);
    p2.PersonAddage(p1).PersonAddage(p1).PersonAddage(p1);


    cout << p2.age << endl;
}

int main()
{
    test01();

    return 0;
}


void test01()
{
    Person p1(10);
    Person p2(25);
    Person &p3 = p2;
    p3=p2.PersonAddage(p1);
    p3.PersonAddage(p1).PersonAddage(p1);

    cout << p2.age << endl;
    cout << p3.age << endl;

}

p116 空指针访问成员函数

在这里插入图片描述
在这里插入图片描述

p117 Const修饰成员函数

在这里插入图片描述
在这里插入图片描述
下图的函数即为常函数:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p118 全局函数 做友元

第一种情况:用全局函数作为好朋友

在这里插入图片描述
在这里插入图片描述
只要上面的那条语句写到类中最上面就可以了,也不需要public啥的

#include <iostream>

#include <string>

using namespace std;


class Building
{
    //放在类中最前面,这个全局函数是Building类的好朋友,可以访问其私有成员
    friend void goodGay(Building *build);

    public:
    //无参构造函数
        Building()
        {
        m_SittingRoom = "客厅";
        m_BedRoom = "卧室";
        }


        string m_SittingRoom;
    private:
        string m_BedRoom;
};

//全局函数
void goodGay(Building *build)
{
    cout << build->m_SittingRoom << endl;
    cout << build->m_BedRoom << endl;
}

void test01()
{
    Building build1;
    goodGay(&build1);
}
int main()
{
    test01();
    return 0;
}

p119 让类做友元

第二中情况,让类做友元

在这里插入图片描述
在这里插入图片描述

#include <iostream>

#include <string>

using namespace std;

class Building;//先声明类Building
class GoodGay//定义类
{
    public:
        GoodGay();
        void visit();

        Building *building;
};

class Building
{
    //GoodGay类是本类的好朋友,
    //其函数可以访问Building类的私有成员 公有成员本来就可以访问
    friend class GoodGay;

public:
    Building();
    string m_SittingRoom;

private:
    string m_BedRoom;
};
//类外写成员函数
GoodGay::GoodGay()
{
    //创建建筑物对象
    building = new Building;
}
//类外写成员函数
void GoodGay::visit()
{
    cout << "正在访问" << building->m_SittingRoom << endl;
    cout << "正在访问" << building->m_BedRoom << endl;

}
//类外写成员函数
Building::Building()
{
    m_BedRoom = "卧室";
    m_SittingRoom = "客厅";
}

void test01()
{
    GoodGay gg;
    gg.visit();

}

int main()
{
    test01();

    return 0;
}

p120 成员函数做友元

第三种情况: 让成员函数做友元

成员函数类外实现或类内实现都可以

在这里插入图片描述

#include <iostream>

#include <string>

using namespace std;

class Building;//先声明类Building
class GoodGay//定义类
{
    public:
        GoodGay();
        void visit1(); //让visit函数可以访问Building中的私有成员
        void visit2();//让visit2函数不可以访问Building中的私有成员

        Building *building;
};

class Building
{
    friend void GoodGay::visit1();

public:
    Building();
    string m_SittingRoom;

private:
    string m_BedRoom;
};
//类外写成员函数
GoodGay::GoodGay()
{
    //创建建筑物对 创建一个Building对象在堆区
    building = new Building;
}
//类外写成员函数
void GoodGay::visit1()
{
    cout << "visit1正在访问" << building->m_SittingRoom << endl;
    cout << "visit1正在访问" << building->m_BedRoom << endl;

}

void GoodGay::visit2()
{
    cout << "visit2正在访问" << building->m_SittingRoom << endl;
    // cout << "正在访问" << building->m_BedRoom << endl;

    
}
//类外写成员函数
Building::Building()
{
    m_BedRoom = "卧室";
    m_SittingRoom = "客厅";
}



void test01()
{
    GoodGay gg;
    gg.visit1();
    gg.visit2();
}

int main()
{
    test01();

    return 0;
}

在这里插入图片描述
如果不是友元,那么只能访问公共属性

p121 加法运算符重载

两种重载方式,一种是成员函数,另一种是全局函数

在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;



class Person
{
    public:
    // //在public下
    // //方式1:通过成员函数重载+号
    //     Person operator+(Person &p)
    //     {
    //         Person temp;
    //         temp.m_A = this->m_A + p.m_A;
    //         temp.m_B = this->m_B + p.m_B;
    //         return temp;
    //     }

        
        int m_A;
        int m_B;
};
//方式2:通过全局函数重载+号
Person operator+(Person &p1, Person &p2)
{
    Person temp;
    temp.m_A = p1.m_A + p2.m_A;
    temp.m_B = p1.m_B + p2.m_B;
    return temp;
}

//函数重载的版本
Person operator+(Person &p1,int num)
{
    Person temp;
    temp.m_A = p1.m_A + num;
    temp.m_B = p1.m_B + num;
    return temp;
}


void test01()
{
    Person p1, p2;
    p1.m_A = 11;
    p1.m_B = 22;
    p2.m_A = 11;
    p2.m_B = 22;

    Person p3;
    p3 = p1 + p2;
    cout << p3.m_A << "\t" << p3.m_B << endl;

    Person p4 = p1 + 10;
    cout << p4.m_A << "\t" << p4.m_B << endl;

}

int main()
{

    test01();
    return 0;
}

两种方式的重载本质调用

在这里插入图片描述
在这里插入图片描述

运算符也可以发生函数重载
函数重载的概念回忆一下::

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

p122 左移运算符重载

在这里插入图片描述

一般不使用第一种方式,也就是成员函数实现重载,原因如下:

在这里插入图片描述

cout:标准的输出流对象 类:ostream
cin: 标准的输入流对象 类:istream

因为cout对象全局只有一个,所以需要引用的方式传递进来,值传递的话,就会创建(复制一个副本)一个新的对象。

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

输出流不能拷贝,也就是说要传入输出流对象参数只能地址传递,不能值传递。
流对象不能复制只能引用,记住就好了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;



class Person
{
    public:
        int m_A;
        int m_B;
};


//使用全局函数的方式重载左移运算符
//输出流对象 cout使用引用的方式传递
//注意这里的ostream & 返回类型可以确保返回的是cout本体
ostream & operator<<(ostream & cout,Person &p)
{
    cout << "p.m_A:" << p.m_A << "   "
         << "p.m_B:" << p.m_B << endl;

    return cout;
}

void test01()
{
    Person p1;
    p1.m_A = 15;
    p1.m_B = 25;
    cout << p1 << endl;
    ;
}

int main()
{
    test01();
    return 0;
}

在这里插入图片描述

#include <iostream>

using namespace std;



class Person
{
    friend ostream &operator<<(ostream &cout, Person &p);

private:
    int m_A;
    int m_B;
};


//使用全局函数的方式重载左移运算符
//输出流对象 cout使用引用的方式传递
//注意这里的ostream & 返回类型可以确保返回的是cout本体
ostream & operator<<(ostream & cout,Person &p)
{
    p.m_A = 15;
    p.m_B = 25;
    cout << "p.m_A:" << p.m_A << "   "
         << "p.m_B:" << p.m_B << endl;
    return cout;
    
}

void test01()
{
    Person p1;

    cout << p1 << endl;
    
}

int main()
{
    test01();
    return 0;
}

在这里插入图片描述
在这里插入图片描述

p123 递增运算符重载

在这里插入图片描述

内置的递增++运算符:

前置递增 先对变量进行递增,再进行其他操作。
后置递增,先对变量进行完其他操作,再进行变量递增。

在这里插入图片描述

1、前置递增

返回引用是为了一直对一个对象进行递增操作,否则的话,如果不是返回引用,而是返回值,则每次递增后返回一个新的对象(调用拷贝构造函数,如果没有自己定义的,会进行浅拷贝)。

返回引用是为了一直对一个对象进行递增操作,否则的话,如果不是返回引用,而是返回值,则每次递增后返回一个新的对象(调用拷贝构造函数,如果没有自己定义的,会进行浅拷贝)。

返回引用是为了一直对一个对象进行递增操作,否则的话,如果不是返回引用,而是返回值,则每次递增后返回一个新的对象(调用拷贝构造函数,如果没有自己定义的,会进行浅拷贝)。
在这里插入图片描述
哔哩哔哩链接
在这里插入图片描述

对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数
对象作为返回值不加引用就会调用拷贝构造函数

复习知识点:拷贝构造函数的调用时机
在这里插入图片描述

值返回是相当于对一个新的返回,再操作又继续开个新的重复

2、后置递增

返回值不可以作为函数重载的条件

函数占位参数
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

此例中的移位与上一节课中的不太一样
后置++使用移位运算符重载 不能定义引用 ,因为返回的临时对象temp已被编译器释放,因此只能值传递
在这里插入图片描述

#include <iostream>

using namespace std;



class MyInteger
{
    friend ostream &operator<<(ostream &cout, MyInteger p);
    public:

        MyInteger()
        {
            m_int = 0;
        }

        //前置++ 通过成员函数重载
        //返回的本体对象
        MyInteger & operator++()
        {
            ++m_int;
            return *this;
        }


        //后置递增 通过成员函数重载实现
        //返回的是局部对象 不能使用引用返回,因为temp为局部对象,后置递增执行完就销毁了temp
        MyInteger operator++(int)
        {
            MyInteger temp=*this;
            m_int++;
            return temp;
        }

    private:
        int m_int;
};


//使用全局函数的方式重载左移运算符
//形参中输出流对象 cout使用引用的方式传递
//注意这里的ostream & 返回类型可以确保返回的是cout本体
//MyInteger p
//后置++使用移位运算符重载 不能定义引用 ,因为返回的临时对象temp已被编译器释放,因此只能值传递
ostream & operator<<(ostream & cout,MyInteger p)
{
    cout  << p.m_int << endl;

    return cout;
}

void test01()
{
    MyInteger m_int1;

    cout << ++(++m_int1) << endl;
    cout << m_int1 << endl;

    
}
void test02()
{
    MyInteger m_int2;
    cout << m_int2++ << endl;

    cout << m_int2 << endl;
}

int main()
{
    test01();
    test02();
    return 0;
}

在这里插入图片描述

p124 赋值运算法重载

在这里插入图片描述

一般来说,只要是值拷贝,都会引发深浅拷贝问题
回忆:拷贝构造函数
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

让p2=p1之后,再把p2这个对象传给p3,也就是函数operator=调用完之后还能返回自身(使用return *this返回自身)

在这里插入图片描述

返回本体需要时引用返回,而不是值返回
在这里插入图片描述
此例中若返回值的话,那就是按照自身调用一个拷贝构造函数(默认浅拷贝),创建一个新的对象(副本),而不是对象自身了。我们要返回其引用才是其真正的自身。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

#include <iostream>

using namespace std;

class Person
{
    public:
        //默认构造函数
        Person(int age)
        {
            m_Age = new int(age);
        }
        //析构函数
        ~Person()
        {
            if(m_Age!=NULL)
            {
                delete m_Age;
                m_Age = NULL;
            }
        }
        //重载赋值运算符
        Person & operator=(Person &p)
        {
            if (m_Age!=NULL)
            {
                delete m_Age;
                m_Age = NULL;
            }
            m_Age = new int(*p.m_Age);
            //指向自身的指针是this指针,*解引用
            return *this;//函数调用之后还能返回对象的自身
        }


        int *m_Age;//这个变量因为是指针,所以被开辟到堆区,而不是栈区
};


void test01()
{
    Person p1(18);
    Person p2(22);
    Person p3(33);
    p3=p2 = p1;
    cout << "p1的年龄"<<*p1.m_Age<<endl;
    cout << "p2的年龄"<<*p2.m_Age<<endl;
    cout << "p3的年龄"<<*p3.m_Age<<endl;


}

int main()
{
    int a = 10, b = 20, c = 30;
    c = b = a;
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    cout << "c=" << c << endl;


    test01();

    return 0;
}

p125 关系运算符重载

在这里插入图片描述

#include <iostream>
#include <string>

using namespace std;


class Person
{
    public:

        Person(string name,int age)
        {
            m_Age = age;
            m_Name = name;
        }

        bool operator==(Person &p)
        {
            if (this->m_Age==p.m_Age && this->m_Name==p.m_Name)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        string m_Name;
        int m_Age;
};

void test01()
{
    Person p1("tom1", 22);
    Person p2("tom", 22);
    if(p1==p2)
    {
        cout << "yes" << endl;
    }
    else
    {
        cout << "no" << endl;
    }
}


int main()
{
    test01();

    return 0;
}

p126函数调用运算符重载

仿函数
十分灵活

在这里插入图片描述
在这里插入图片描述
匿名函数对象

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <string>

using namespace std;


class Myprint
{
    public:
        //重载函数调用运算符
        void operator()(string test)
        {
            cout << test << endl;
        }
};

void test01()
{
    Myprint myprint;
    myprint("helloworld");
}


class Add
{
    public:
        void operator()(int num1,int num2)
        {
            cout << num1 + num2 << endl;
            
        }
};

void test02()
{
    Add add;
    add(1, 1);
    Add()(100, 125);//匿名函数对象,Add()相当于匿名对象
}

int main()
{
    // test01();
    test02();
    return 0;
}

p127 继承-基本语法(重点)

继承的技术

在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;
//父类 也就是基类
class Base
{
    public:
        void header()
        {
            cout << "首页、公开课、登录(公共头部)" << endl;
        }

        void footer()
        {
            cout << "帮助中心、联系方式(公共底部)" << endl;
        }

        void leftlist()
        {
            cout << "C++、Python、Java(公共左侧)" << endl;
        }
};

//Java继承Base类
class Java : public Base
{
    public:
        void content()
        {
            cout << "Java 视频资料" << endl;
        }
};



//cpp继承Base类
class Cpp : public Base
{
    public:
        void content()
        {
            cout << "cpp 视频资料" << endl;
        }
};

void test01(Java &p)
{
    cout << "java下载视频的页面" << endl;
    p.header();
    p.footer();
    p.leftlist();
    p.content();
}

void test02(Cpp &p)
{
    cout << "cpp下载视频的页面" << endl;
    p.header();
    p.footer();
    p.leftlist();
    p.content();
}



int main()
{
    Java java1;
    Cpp cpp1;
    test01(java1);
    cout << "-----------------" << endl;
    test02(cpp1);

    return 0;
}

在这里插入图片描述

p128继承方式

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

p129 继承中的对象模型

在这里插入图片描述

在这里插入图片描述
开发人员命令提示工具

在这里插入图片描述

#include <iostream>

using namespace std;


class Base
{
    public:
        int m_A;
    protected:
        int m_B;
    private:
        int m_C;
};


class Son1 : public Base
{
    public:
        int m_D;
};



int main()
{
    int a = 10;
    Base base;
    Son1 son1;
    cout << sizeof(a) << endl;
    cout << sizeof(base) << endl;
    cout << sizeof(son1) << endl;


}

在这里插入图片描述

p130 构造和析构顺序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p131 继承中同名函数处理方式

在这里插入图片描述

在这里插入图片描述
注意是所有的同名函数(包括重载的 都给隐藏掉了)
在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;


class Base
{
    public:
        Base()
        {
            m_A = 10;
        }
        void func()
        {
            cout << "Base func" << endl;
        }
        void func(int a)
        {
            cout << "Son int a func" << endl;
        }

        int m_A;
};

class Son: public Base
{
    public:
        Son()
        {
            m_A = 100;
        }

        void func()
        {
            cout << "Son func" << endl;
        }

        int m_A;
};


//调用同名成员数据
void test01()
{
    Son son1;
    cout << "son的m_A "<< son1.m_A << endl;
    cout << "父类的m_A " << son1.Base::m_A << endl;
}

//调用同名成员函数
void test02()
{
    Son son2;
    son2.func();//同名情况下,调用子类的,加类作用域才调用父类的
    son2.Base::func();
    //错误,因为子类和父类的成员函数重名后,父类的所以这个名称的成员函数被隐藏掉
    //找不到第二个父类的func(int a)函数
    // son2.func(10);
    //加上类作用域就可以啦
    son2.Base::func(10);

}

int main()
{
    test02();
    return 0;
}

p132 继承同名静态成员函数处理方式

在这里插入图片描述
复习 类与对象中的静态成员

在这里插入图片描述

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。

静态成员的访问有两种方式:通过对象访问或者通过类名。
1、通过对象访问

在这里插入图片描述

2、通过类名访问
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;

class Base
{
    public:
        static int m_A;
        static void fun()
        {
            cout << "base func" << endl;
        }
        static void fun(int a)
        {
            cout << "base func int a" << endl;
        }
};

int Base::m_A = 10;

class Son :public Base
{
    public:
        static int m_A;
        static void fun()
        {
            cout << "son fun" << endl;
        }
};

int Son::m_A = 100;

void test01()
{
    Son son;
    //方式一通过对象来访问静态成员数据
    cout << "通过对象访问" << endl;
    cout << "son :" << son.m_A << endl;
    cout << "base :" << son.Base::m_A << endl;


    //方式二 通过类名访问静态成员数据
    cout << "通过类名访问静态成员数据" << endl;
    cout << "son :" << Son::m_A << endl;
    cout << "Base :" << Base::m_A << endl;
    //通过访问son中的父类作用下的m_A
    cout << "Base ::" << Son::Base::m_A << endl;
}


void test02()
{
    //1.
    Son son;
    son.fun();
    son.Base::fun();



    //2.
    Son::fun();
    Son::Base::fun();
    Son::Base::fun(10255);
}

int main()
{
    test02();
    return 0;
}

p133 多继承语法

在这里插入图片描述

在这里插入图片描述

作用域::

p134 菱形继承或者钻石继承

【暂时没学习,用到的时候再学习】
在这里插入图片描述

p135 多态的基本语法

在这里插入图片描述

父类引用指向子类对象
c++中运行父子类之间类型转换
静态多态

在这里插入图片描述
这样就可以实现地址晚绑定 也就是动态多态
在这里插入图片描述

函数重写的意思:(子类的virtual可写可不写)
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:
在这里插入图片描述

#include <iostream>

using namespace std;

//父类或者基类
class Animal
{
    public:
        //虚函数 可以实现地址的晚绑定 也就是动态多态
        virtual void speak()
        {
            cout << "动物在说话" << endl;
        }
};


//子类或者派生类
class Cat : public Animal
{
    public:
    //子类重写父类中的虚函数
        void speak()
        {
            cout << "小猫在说话" << endl;
        }
};
//子类或者派生类

class Dog : public Animal
{
    public:
        void speak()
        {
            cout << "小狗在说话" << endl;
        }
};

void DoSpeak(Animal &p)//父类指针或者引用指向子类对象
{
    p.speak();//现在speak等于是多种形态了
}

void test01()
{
    Cat cat1;
    DoSpeak(cat1);
    Dog dog1;
    DoSpeak(dog1);
}

int main()
{
    test01();
    return 0;
}

p136

四个字节一般是整形变量 指针等
在这里插入图片描述
当用父类指针或者引用指向子类对象,调用speak时会调用小猫会说话。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

p137 多态案例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>

using namespace std;
//多态的使用

//父类 抽象的一个类
class AbstractCalculator
{
    public:
        virtual int GetResult()
        {
            return 0;
        }

        int m_Num1;
        int m_Num2;
};

//加法
class AddCalculator : public AbstractCalculator
{
    public:
        int GetResult()
        {
            return m_Num1 + m_Num2;
        }
};

// 减法
class SubCalculator : public AbstractCalculator
{
    public:
        int GetResult()
        {
            return m_Num1 - m_Num2;
        }
};

// 乘法
class MulCalculator : public AbstractCalculator
{
    public:
        int GetResult()
        {
            return m_Num1 * m_Num2;
        }
};



void test01()
{
    //实现加法
    AbstractCalculator *abc = new AddCalculator;
    abc->m_Num1 = 15;
    abc->m_Num2 = 35;
    cout << abc->GetResult() << endl;
    //用完后记得销毁
    delete abc;

    abc = new SubCalculator;
    abc->m_Num1 = 100;
    abc->m_Num2 = 90;
    cout << abc->GetResult() << endl;
}

int main()
{
    test01();
    return 0;
}

p138 纯虚函数和抽象类

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

p139 多态 案例

在这里插入图片描述

在这里插入图片描述
**都是同样一个makedrink接口
**

在这里插入图片描述

#include <iostream>

using namespace std;

//多态的使用
//多态案例2  制作饮品

//基类 也就是父类,因为里面的成员函数有纯虚函数,所以变成抽象类
class AbstractDrinking
{
    public:
        //成员函数写成纯虚函数 基类也就变成抽象类

        //煮水
        virtual void Boil() = 0;
        //冲泡
        virtual void Brew() = 0;
        //倒入杯子
        virtual void PourInCup() = 0;
        //加入辅料
        virtual void PutSomething() = 0;


        //制作饮品
        void MakeDrinking()
        {
            Boil();
            Brew();
            PourInCup();
            PutSomething();
        }
};


//制作咖啡
class MakeCoffee : public AbstractDrinking
{
    public:
        //成员函数写成纯虚函数 基类也就变成抽象类

        //煮水
        void Boil()
        {
            cout << "煮水" << endl;
        }
        //冲泡
        void Brew()
        {
            cout << "冲泡咖啡" << endl;
        }
        //倒入杯子
        void PourInCup()
        {
            cout << "将咖啡倒入杯中" << endl;
        }
        //加入辅料
        void PutSomething()
        {
            cout << "将辅料加入到咖啡中" << endl;
        }

};

//制作茶水
class MakeTea : public AbstractDrinking
{
    public:
        //成员函数写成纯虚函数 基类也就变成抽象类

        //煮水
        void Boil()
        {
            cout << "煮水" << endl;
        }
        //冲泡
        void Brew()
        {
            cout << "冲泡茶叶" << endl;
        }
        //倒入杯子
        void PourInCup()
        {
            cout << "将茶水倒入杯中" << endl;
        }
        //加入辅料
        void PutSomething()
        {
            cout << "将辅料加入到茶水中" << endl;
        }

};

void DoWork(AbstractDrinking *abs)
{
    abs->MakeDrinking();
}

void test01()
{
    AbstractDrinking *abs1 = new MakeCoffee;
    DoWork(abs1);
    // DoWork(new MakeCoffee);
    delete abs1;

    abs1 = new MakeTea;
    DoWork(abs1);
    // DoWork(new MakeTea);
    delete abs1;

}


int main()
{
    test01();
    return 0;
}

p140 虚析构 纯虚析构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

纯虚析构函数需要注意的问题

在这里插入图片描述
在这里插入图片描述

在多态使用中:
不管是虚析构还是纯虚析构 都是为了解决子类中析构代码调用不到的问题

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

p142 案例

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#include <iostream>

using namespace std;

//多态的使用
//多态案例

//三个抽象类

//cpu抽象类
class Cpu
{
    public:
        virtual void Calculator() = 0;
};
//显卡抽象类
class VideoCard
{
    public:
        virtual void display() = 0;
};
//存储抽象类
class Memory
{
    public:
        virtual void storage() = 0;
};






//电脑类  
class Computer
{
    public:
        //构造函数
        Computer(Cpu *cpu, VideoCard *vc, Memory *mem)
        {
            cout << "Computer的构造" << endl;
            m_cpu = cpu;
            m_vc = vc;
            m_mem = mem;
        }

        void Work()
        {
            m_cpu->Calculator();
            m_mem->storage();
            m_vc->display();
        }


        //析构函数
        ~Computer()
        {
            cout << "Computer的析构" << endl;
            if(m_cpu!=NULL)
            {
                delete m_cpu;
                m_cpu = NULL;
            }

            if(m_vc!=NULL)
            {
                delete m_vc;
                m_vc = NULL;
            }

            if(m_mem!=NULL)
            {
                delete m_mem;
                m_mem = NULL;
            }

        }

        private : 
            Cpu *m_cpu;
            VideoCard *m_vc;
            Memory *m_mem;
};



//Intel厂商
class IntelCpu : public Cpu
{
    public:
        //派生类重写函数
         void Calculator()
         {
            cout << "Intel的cpu开始计算了" << endl;
         }
};
class IntelVideoCard : public VideoCard
{
    public:
         void display()
         {
            cout << "Intel的显卡开始工作了" << endl;
         }
};
class IntelMemory : public Memory
{
    public:
         void storage()
         {
             cout << "Intel的内存开始工作了" << endl;
         }
};



//Lenovo厂商
class LenovoCpu : public Cpu
{
    public:
         void Calculator()
         {
             cout << "Lenovo的cpu开始计算了" << endl;
         }
};
class LenovoVideoCard : public VideoCard
{
    public:
         void display()
         {
             cout << "Lenovo的显卡开始工作了" << endl;
         }
};
class LenovoMemory : public Memory
{
    public:
         void storage()
         {
             cout << "Lenovo的内存开始工作了" << endl;
         }
};



void test01()
{
    //第一台电脑零件
    //多态的条件之一,父类指针指向子类对象
    //堆区的数据手动开启 需要手动释放!!!!!!
    Cpu *intelCpu = new IntelCpu;
    VideoCard *videoCard = new IntelVideoCard;
    Memory *memory = new IntelMemory;

    //创建第一台电脑
    Computer *computer = new Computer(intelCpu, videoCard, memory);
    computer->Work();
    //释放下面这个对象时 执行器析构函数
    delete computer;


    //创建第二台电脑    换了个写法 直接在实参出new ,,,
    Computer *computer2 = new Computer(new LenovoCpu, new LenovoVideoCard, new LenovoMemory);
    computer2->Work();
    delete computer2;
}

int main()
{
    test01();

    return 0;
}

p143文件操作-文本文件-写文件

在这里插入图片描述
五步法写文件
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;

#include <fstream>

//练习写文件

void test01()
{
    //1.包含头文件

    //2.创建流对象
    ofstream ofs;

    //3.指定打开方式
    ofs.open("text.txt", ios::out);

    //4.写内容 换行照样好使

    ofs << "sdawsd" << endl;
    ofs << "张帅克拉拉啊" << endl;

    //5.关闭文件

    ofs.close();
}

int main()
{
    test01();

    return 0;
}

p144文件操作-文本文件-读文件

在这里插入图片描述

读文件共有四种方式,第四种如下:
在这里插入图片描述

#include <iostream>
using namespace std;

#include <fstream>
#include <string>
//练习读文件

void test01()
{
    //1.包含头文件

    //2.创建流对象
    ifstream ifs;

    //3.指定打开方式
    ifs.open("text.txt", ios::in);
    //判断文件是否打开成功
    if(!ifs.is_open())
    {
        cout << "文件打开失败" << endl;
        return;
    }
    //4.读文件
    //第一种
    // char buf[1024] = {0};
    // while (ifs>>buf)
    // {
    //     cout << buf << endl;
    // }
    cout << "---------" << endl;
    //第二种方式
    // char buf[1024] = {0};
    // while(ifs.getline(buf,sizeof(buf)))
    // {
    //     cout << buf << endl;

    // }

    //第三种
    string buf;//字符串变量
    while(getline((ifs),buf))
    {
        cout << buf << endl;
    }

    //5.关闭文件

    ifs.close();
}

int main()
{
    test01();

    return 0;
}

在这里插入图片描述

p145 p146 二进制文件的读取和写入

=暂时未学习

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值