c++基础知识复习(1)

前期知识准备

1 构造函数

在这里插入图片描述

在这里插入图片描述

(1)默认构造函数:没有参数传入,也没有在类里面声明

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

在这里插入图片描述

(2)手动定义默认构造函数:没有参数传入,但是在类里面进行了声明

可以在类外实现或者类内实现
在这里插入图片描述
以下案例是类外实现了手动定义的默认构造函数
在这里插入图片描述
构造函数的调用:不需要手动调用,定义类对象的时候就实现了自动调用

int main()
{Human zhangshan; 定义对象,此处会自动调用构造函数......
}

(2)自定义重载构造函数,名字相同,内容不同

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

(3)拷贝构造函数

拷贝构造函数的两种调用方式
在这里插入图片描述
拷贝构造函数的定义,关键字const以及引用符号&,引用符号&后面可接变量,也可以不接
在这里插入图片描述
拷贝被造函数的类外定义
在这里插入图片描述

(a) !!!!如果不定义拷贝函数而使用了拷贝功能,c++会自动生成一个拷贝函数,实现的是浅拷贝

直接将数据拷贝过去,如果只是普通的数据类型是没有关系的,但是如果是指针,就会出现问题,以下列案例为例:
假设一开始定义了3个类,将如花拷贝给张山的girlfriend变量,也就是girlfriend指向如花
在这里插入图片描述

没有定义拷贝函数的情况下,实现的拷贝,浅拷贝,也就是不同类对象指向同一块内存地址,前面完成拷贝之后,再修改h1的值,还是导致h2,h3的值都被修改,这将导致错误。正确的逻辑是,拷贝之后,h1,h2,h3之间的值不再相互干扰除非再次执行赋值函数
#include <iostream>
#include<string.h>
#include<graphics.h>using namespace std;
#define ADDR_LEN 64  //宏class Human {
public:Human();Human(int salary);void description();void setAddr(char *addr);private:int age = 18;int salary;char *addr;
};void Human::description()
{cout << "addr = " << addr << endl;
}Human::Human(int salary)
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}Human::Human()
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}void Human::setAddr(char* addr)
{if (!addr){return;}strcpy_s(this->addr, ADDR_LEN, addr);
}int main(void)
{Human h1;Human h2 = h1;Human h3(h1);h1.description();h2.description();h3.description();cout << "修改h1地址之后" << endl;char addrrr[ADDR_LEN] = "Ammerica";h1.setAddr(addrrr);h1.description();h2.description();h3.description();system("pause");return 0;
}

在这里插入图片描述

定义拷贝函数的情况下,给指针变量单独开辟新的空间,使得新的对象和旧的对象在调用该指针成员函数的时候,不再指向同一块内存
#include <iostream>
#include<string.h>
#include<graphics.h>using namespace std;
#define ADDR_LEN 64  //宏class Human {
public:Human();Human(int salary);void description();void setAddr(char *addr);/Human(const Human &other);  //自定义拷贝函数,深拷贝/
private:int age = 18;int salary;char *addr;
};/
Human::Human(const Human& other)
{age = other.age;salary = other.salary;//addr是指针,要为其分配一个独立的内存,来存放新的对象的addr,使得新的对象和旧的对象在调用该指针成员函数的时候,不再指向同一块内存this->addr = new char[ADDR_LEN];strcpy_s(this->addr, ADDR_LEN, other.addr);
}
/void Human::description()
{cout << "addr = " << addr << endl;
}Human::Human(int salary)
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}Human::Human()
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}void Human::setAddr(char* addr)
{if (!addr){return;}strcpy_s(this->addr, ADDR_LEN, addr);
}int main(void)
{Human h1;Human h2 = h1;Human h3(h1);h1.description();h2.description();h3.description();cout << "修改h1地址之后" << endl;char addrrr[ADDR_LEN] = "Ammerica";h1.setAddr(addrrr);h1.description();h2.description();h3.description();system("pause");return 0;
}

在这里插入图片描述

(b) 什么时候拷贝构造函数会被调用

在这里插入图片描述

情形1:函数调用时,函数的实参是对象,形参不是引用类型,会调用拷贝构造函数导致额外的开销,这种情况推荐是使用引用,将不会调用拷贝构造函数,不会创新新的空间导致额外的开销

在这里插入图片描述
如果函数声明改成了 void showMsg(Human &man)则不对调用自定义构造函数,而是调用自动生成的构造函数

使用引用相当于传递了指针,可以在这个函数里面修改外面的参数。这样很危险,比如,下列函数的本意是打印信息,而不是修改成员函数,这样将导致打印的成员函数的值出现错误

void showMsg(Human &man)
{cout < man.getName() << endl;man.setAddr("Janpa“);
}

添加const修饰,使得在函数内不能修改成员函数
也就是void showMsg(const Human &man)
由于const修饰了man。man.getName()将会报错,因为man.getName()不是const类型的函数
所以 在定义的时候需要将string getName(); 改成string getName() const; 则表示不能在函数里面修改成员变量

#include <iostream>
#include<string.h>
#include<graphics.h>using namespace std;
#define ADDR_LEN 64  //宏class Human {
public:Human();Human(int salary);void description();void setAddr(char *addr);Human(const Human &other);  //自定义拷贝函数,深拷贝
private:int age = 18;int salary;char *addr;
};Human::Human(const Human& other)
{age = other.age;salary = other.salary;//addr是指针,要为其分配一个独立的内存,来存放新的对象的addr,使得新的对象和旧的对象在调用该指针成员函数的时候,不再指向同一块内存this->addr = new char[ADDR_LEN];strcpy_s(this->addr, ADDR_LEN, other.addr);cout << "调用了拷贝构造函数" << endl;
}void Human::description()
{cout << "addr = " << addr << endl;cout << "salary = " << salary << ",age = " << age << endl;
}Human::Human(int salary)
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}Human::Human()
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");
}void Human::setAddr(char* addr)
{if (!addr){return;}strcpy_s(this->addr, ADDR_LEN, addr);
}void showMsg(Human man)
{cout << "showMsg :  " << endl;man.description();
}int main(void)
{Human h1;//Human h2 = h1;showMsg(h1);//Human h3(h1);//h1.description();//h2.description();//h3.description();//cout << "修改h1地址之后" << endl;char addrrr[ADDR_LEN] = "Ammerica";h1.setAddr(addrrr);//h1.description();//h2.description();//h3.description();system("pause");return 0;
}

在这里插入图片描述

情形2:函数的返回值是类的情况,且这个类不是引用会调用构造函数才能构造一个对象。如果返回值是类引用,则是指针,直接使用原始数据,而不是先开辟空间来存放数据之后再使用,这样就不需要构建一个对象

下面这种情况是返回值是类的情况,会调用自定义的构造函数

Human getBetterMan(Human& man1, Human& man2)
{if (man1.getSalary() > man2.getSalary()){return man1;}else{return man2;}
}int main(void)
{Human h1(35000);Human h2(25000);getBetterMan(h1, h2);  //这里这么写,会返回一个临时对象,但是没有东西接收,有一个对象需要调用构造函数才能构造一个对象,此处调用的是拷贝构造函数system("pause");return 0;
}

下面这种情况是返回值是类引用,不会调用自定义的构造函数

const Human& getBetterMan(const Human& man1, const Human& man2)
{if (man1.getSalary() > man2.getSalary()){return man1;}else{return man2;}
}
  • const常见错误

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

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

情形3:初始化成员列表

在这里插入图片描述

2 析构函数

主要是动态指针内存的清理。
析构函数不能带参数。只有一种形式
在这里插入图片描述

class Human {
public:Human();Human(int salary);void description() const;void setAddr(char* addr);void showMsg(const Human& man);int getSalary() const;Human(const Human& other);  //自定义拷贝函数,深拷贝//析构函数~Human();  //析构函数不能带参数
private:int age = 18;int salary;char* addr;
};Human::~Human()
{cout << "调用析构函数 : " << this << endl;delete addr;
}

3 静态成员

3.1 静态成员

统计总共创建了多少个类对象,什么时候使用静态成员,当需要使用的数据是涉及到所有对象的时候,所有对象都要使用的时候,就需要定义静态成员函数
在这里插入图片描述

方法1:定义全局变量
#pragma once#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏
extern int HumanCount; // 全局变量别人都可以修改,可能重名且不安全,开发的时候全局变量越少越好class Human {
public:Human();Human(int salary);void description() const;void setAddr(char* addr);void showMsg(const Human& man);int getSalary() const;Human(const Human& other);  //自定义拷贝函数,深拷贝//析构函数~Human();  //析构函数不能带参数
private:int age = 18;int salary;char* addr;//int HumanCount;  //直接在这里使用这样是不行的,每个对象有自己的HumanCount,没办法做对象的计数static int HumanCount;  //静态成员变量的内存和类本身并不是一块内存
};
#pragma once#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏
extern int HumanCount; // 全局变量别人都可以修改,可能重名且不安全,开发的时候全局变量越少越好class Human {
public:Human();Human(int salary);void description() const;void setAddr(char* addr);void showMsg(const Human& man);int getSalary() const;Human(const Human& other);  //自定义拷贝函数,深拷贝//析构函数~Human();  //析构函数不能带参数
private:int age = 18;int salary;char* addr;//int HumanCount;  //直接在这里使用这样是不行的,每个对象有自己的HumanCount,没办法做对象的计数static int HumanCount;  //静态成员变量的内存和类本身并不是一块内存
};
#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏
#include "Human.h"int HumanCount = 0;Human::~Human()
{cout << "调用析构函数 : " << this << endl;delete addr;
}int Human::getSalary() const
{return salary;
}Human::Human(const Human& other)
{age = other.age;salary = other.salary;//addr是指针,要为其分配一个独立的内存,来存放新的对象的addr,使得新的对象和旧的对象在调用该指针成员函数的时候,不再指向同一块内存this->addr = new char[ADDR_LEN];strcpy_s(this->addr, ADDR_LEN, other.addr);cout << "调用了自定义拷贝构造函数" << endl;
}void Human::description() const
{cout << "addr = " << addr << endl;cout << "salary = " << salary << ",age = " << age << endl;
}Human::Human()
{salary = 20000;this->addr = new char[ADDR_LEN];  //指针需要进行初始化分配空间strcpy_s(this->addr, ADDR_LEN, "china");HumanCount++;
}Human::Human(int salary)
{this->salary = salary;HumanCount++;
}void Human::setAddr(char* addr)
{if (!addr){return;}strcpy_s(this->addr, ADDR_LEN, addr);
}
方法2:定义静态成员函数

静态成员变量的内存和类本身并不是一块内存
在类里面定义静态成员
在这里插入图片描述

静态成员的初始化,然后就像使用全局变量一样使用他就可以
在这里插入图片描述
在这里插入图片描述

如果使用const标识的静态成员函数
静态成员函数在定义的时候就可以直接初始化,但是非const的静态成员函数定义的时候不能初始化

const static int humanCount = 0;  或者去.cpp咯i面
const int Human::humanCount = 0;  
#pragma once#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏class Human {
public:Human();Human(int salary);void description() const;void setAddr(char* addr);void showMsg(const Human& man);int getSalary() const;Human(const Human& other);  //自定义拷贝函数,深拷贝//析构函数~Human();  //析构函数不能带参数int getHumanCount();private:int age = 18;int salary;char* addr;//int HumanCount;  //直接在这里使用这样是不行的,每个对象有自己的HumanCount,没办法做对象的计数static int HumanCount;  //静态成员变量的内存和类本身并不是一块内存
};
#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏
#include "Human.h"//对类的静态成员初始化
int Human::HumanCount = 0;
。。。。int Human::getHumanCount()
{return HumanCount;
}

void showMsg(const Human &man)
{cout << "showMsg :  " << endl;man.description();
}void test()
{Human h1;{Human h2;// h2先死,然后h1死}cout << "test() end." << endl;
}int main(void)
{Human f1, f2, f3, f4;Human F4[4] = { f1, f2, f3, f4};test();cout << "总人数 : " << f1.getHumanCount() << endl;system("pause");return 0;
}

4 静态成员函数

使用常规的成员函数调用静态成员变量存在一个问题,见void showMsg()函数


void showMsg()
{//这里为了调用getHumanCount来调用静态成员变量,而定义了一个新的对象,导致最后的计数是3,但是实际在test里面只实际创建了两个对象,整个函数里创建这个对象是对于的Human tem1;cout << "总人数 : " << tem1.getHumanCount() << endl;
}void test()
{Human h1;Human h2;
}int main(void)
{test();showMsg();system("pause");return 0;
}

#####################################
定义静态成员函数

#pragma once#include<string.h>
#include <iostream>
using namespace std;
#define ADDR_LEN 64  //宏class Human {
public:static int getHumanCount();private://int HumanCount;  //直接在这里使用这样是不行的,每个对象有自己的HumanCount,没办法做对象的计数static int HumanCount;  //静态成员变量的内存和类本身并不是一块内存
};
//对类的静态成员初始化
int Human::HumanCount = 0;int Human::getHumanCount()
{return HumanCount;
}
void showMsg()
{//static定义的变量或者函数,不属于某一个具体的对象,而是类的东西,可以直接通过类访问cout << "总人数 : " << Human::getHumanCount() << endl;
}void test()
{Human h1;Human h2;//对象也可以直接访问静态成员函数cout << "总人数 : " << h1.getHumanCount() << endl;
}int main(void)
{test();showMsg()system("pause");return 0;
}

在这里插入图片描述
静态成员函数如果直接访问类的成员变量,那就不知道访问的是哪一个具体对象的成员变量,是不行的

  • 静态的成员函数,不能调用非静态的成员函数(static定义的一般是类的东西,共用的东西,而用户可以创建很多类对象,每个类对象可以定义自己的变量,所以用公共的东西去访问个人的东西是不合理的)
    在这里插入图片描述
  • 静态成员函数不能访问非静态成员函数(static定义的一般是类的东西,共用的东西,而用户可以创建很多类对象,每个类对象可以定义自己的变量,所以用公共的东西去访问个人的东西是不合理的)
    -、

5 组合和聚合

组合和聚合最大的区别在于,
前者是类之间是高度关联的,同生同灭,一起创建,一起销毁
后者类之间互不关联

5.1 组合,一个类里面调用另一个类,非指针的形式

学习要点

  • 一个类在另一个类里面的定义方式
  • 一个类里面对另一个类的初始化方式

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

主函数

#include<string>
#include<stdio.h>
#include<iostream>
#include "Computer.h"
using namespace std;
void test()
{Computer myComputer("intel","i9",1000,8);
}
int main()
{test();return 0;
}

Computer.h, 一个类在另一个类里面的定义方式

#pragma once
#include<string>
#include<stdio.h>
#include<iostream>
#include "Cpu.h"
using namespace std;
//class Cpu;
class Computer
{
public:Computer(const char* cpuBrand, const char* cpuVersion, int hardDisk, int memory);~Computer();
private://声明方式1Cpu cpu;  //如果声明用#include "Cpu.h",这里定义了一个对象,那就会需要自动调用它的构造函数,因此必须要包含头文件//声明方式2,下面是定义了一个指针,还没有创建对象,指针可以指向任何东西,所以不需要包含头文件//Cpu *cpu;  //要用class Cpu声明;int hardDisk;  //硬盘,单位 Gint memory;  // 内存
};

Computer.cpp, 一个类里面对另一个类的初始化方式

#include "Computer.h"
Computer::Computer(const char* cpuBrand, const char* cpuVersion,int hardDisk, int memory):cpu(cpuBrand, cpuVersion)  //对成员函数对象初始化的方式1
{//this->cpu = Cpu(cpuBrand, cpuVersion); 对成员函数对象初始化的方式2this->hardDisk = hardDisk;this->memory = memory;
}
Computer::~Computer()
{}

Cpu.h

#pragma once
using namespace std;
#include<string>
class Cpu
{
public:Cpu(const char *brand= "intel", const char* version = "i5");~Cpu();
private:string brand; //品牌string version; //型号
};

Cpu.cpp

#include "Cpu.h"
using namespace std;
#include<string>
#include<iostream>
Cpu::Cpu(const char* brand, const char* version)
{this->brand = brand;this->version = version;//打印当前函数名cout << __FUNCTION__ << endl;
}
Cpu::~Cpu()
{cout << __FUNCTION__ << endl;
}

5.1.2 组合,一个类里面调用另一个类,指针的形式

Computer.h

#pragma once
#include<string>
#include<stdio.h>
#include<iostream>using namespace std;class Cpu;class Computer
{
public:Computer(const char* cpuBrand, const char* cpuVersion, int hardDisk, int memory);~Computer();private://声明方式1//Cpu cpu;  //如果声明用#include "Cpu.h",这里定义了一个对象,那就会需要自动调用它的构造函数,因此必须要包含头文件//声明方式2,下面是定义了一个指针,还没有创建对象,指针可以指向任何东西,所以不需要包含头文件Cpu *cpu;  //要用class Cpu声明;int hardDisk;  //硬盘,单位 Gint memory;  // 内存
};

Computer.cpp

#include "Computer.h"Computer::Computer(const char* cpuBrand, const char* cpuVersion,int hardDisk, int memory)
{this->cpu = new Cpu(cpuBrand, cpuVersion); //对成员函数对象初始化的方式2this->hardDisk = hardDisk;this->memory = memory;}Computer::~Computer()
{delete cpu;
}

5.2 聚合

下面案例对VoiceBox* box;的调用就是所谓聚合关系,Computer的销毁不会引起VoiceBox的销毁

class Computer
{
public:Computer(const char* cpuBrand, const char* cpuVersion, int hardDisk, int memory);~Computer();void addVoiceBox(VoiceBox* box);
private://声明方式1//Cpu cpu;  //如果声明用#include "Cpu.h",这里定义了一个对象,那就会需要自动调用它的构造函数,因此必须要包含头文件//声明方式2,下面是定义了一个指针,还没有创建对象,指针可以指向任何东西,所以不需要包含头文件Cpu *cpu;  //要用class Cpu声明;VoiceBox* box;int hardDisk;  //硬盘,单位 Gint memory;  // 内存
};
#include "Computer.h"Computer::Computer(const char* cpuBrand, const char* cpuVersion,int hardDisk, int memory)
{this->cpu = new Cpu(cpuBrand, cpuVersion); //对成员函数对象初始化的方式2this->hardDisk = hardDisk;this->memory = memory;Computer::~Computer()
{delete cpu;
}
void Computer::addVoiceBox(VoiceBox* box)
{this->box = box;
}

6 vector 常见错误

下列案例,对同一个人的信息打印,结果却不一样
在这里插入图片描述
在这里插入图片描述

#include<string>
#include<stdio.h>
#include<iostream>
#include <vector>
using namespace std;class Man {
public:Man() {};void play(){count += 10;cout << "I am playing ..." << endl;}int getDrinbgkCount()const{return count;}
private:int count = 0;  //一共喝了多少杯
};
int main()
{Man zhangfei, guanyu, liubei;vector<Man> men;men.push_back(liubei);men.push_back(guanyu);men.push_back(zhangfei);men[0].play();cout <<  men[0].getDrinbgkCount() << endl;cout << liubei.getDrinbgkCount() << endl;return 0;
}

在这里插入图片描述

7 继承和派生,两个是一回事,本质是相同的,

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

  • 案例,男孩和女孩类有很多相同的代码, int getAge() const; string getName() const;如果代码量大,可能会有更多的冗余
    男孩类
#pragma once
#include<string>
#include<vector>using namespace std;
class Girl;class Boy
{
public:Boy();Boy(int age, string name, int salary);~Boy();int getAge() const;string getName() const;int getSalary() const;bool satisfied(const Girl& girl)const;string description() const;//静态成员函数可以通过类名来调用,不需要通过创建类对象来调用,这个功能在这里很重要。程序的逻辑是,直接添加一个对象,而不能通过先创建//一个对象之后,再用这个对象来调用这个添加函数,这个逻辑是不合理的,所以要使用静态成员函数static void inputBoys(vector< Boy>&boys);
private:int age;string name;int salary;
};

女孩类

#pragma once
#include<string>
#include<vector>
using namespace std;
class Boy;class Girl
{
public:Girl();Girl(int age, string name, int yanzhi);~Girl();//如果成员函数不会改变你的传入的变量,最好加个constint getAge() const; string getName() const;int getYanzhi() const;bool satisfied(const Boy &boy)const;string description() const;static void inputGirls(vector< Girl>& girls);
private:int age;string name;int yangZhi;
};

7.1 继承和派生的实现

在这里插入图片描述

  • 主要知识点1
//创建Son构造函数时,需要手动调用父类的构造函数,用来初始化父类的数据
// r如果不手动调用,就会默认调用父类的默认构造函数,也就是啥参数都不传的Father()
//再调用自己Son的构造函数,初始化自己的数据
Son::Son(const char* name, int age, const char* game):Father(name,age)
{cout << __FUNCTION__ << endl;this->game = game;//name和age在父类里面已经初始化了,子类就不需要再初始化了
}
  • 主要知识点2:重载什么时候使用,父类的某个成员函数功能不能满足子类,子类想扩展或改良父类的这个函数,就会重载,再再子类重新写一遍这个函数

子类不能访问父类的私有成员函数或变量,但是又想访问父类的私有成员,可以将父类的私有成员改成protected,或者用父类的公有成员函数实现间接访问父类的私有成员函数,如父类的name是私有变量,子类想要访问的话,可以通过父类的getName函数获取父类的name名字

//父类和子类有一个同名的成员函数,调用的时候,会先在自己的成员函数列表里面找,如果找不到,才会去父类的列表里面找
string Son::description()
{//son类继承父类,不能访问父类的私有成员// 	//stringstream ret;//ret << "name:" << name << "-年龄:" << age;//return ret.str();// 如果想用重载,但是又想访问父类的私有成员,可以将父类的私有成员改成protected,或者用父类的公有成员函数实现间接访问父类的私有成员函数stringstream ret;ret << "name:" << getName() << "-年龄:" << getAge() << ", game:" << getGame();return ret.str();
}

——————————————————————————————————————————
主函数

#include <iostream>
#include "Father.h"
#include "Son.h"
#include "string"
using namespace std;int main(void){Father wjl("王健林", 68);Son wsc("王思聪", 32, "电竞");cout << wjl.description() << endl;cout << wsc.description() << endl;return 0;
}

#pragma once
#include <string>
#include<iostream>using namespace std;class Father
{
public:Father(const char *name, int age);~Father();string getName();int getAge();string description();private:string name;int age;
};************************************************************************************
#include "Father.h"
#include <sstream>Father::Father(const char* name, int age)
{cout << __FUNCTION__ << endl;this->name = name;this->age = age;
}Father::~Father()
{
}string Father::getName()
{return name;
}int Father::getAge()
{return 0;
}string Father::description()
{stringstream ret;ret << "name:"<< name <<  "-年龄:" << age ;return ret.str();}
#pragma once
#include "Father.h"class Son: public Father
{
public:Son(const char*name, int age, const char*game);~Son();string getGame();string description();  //父类的这种方法不能满足子类的要求,但是文件名又不想修改,想修改函数里面的内容
private:string game;
};*************************************************************
#include "Son.h"
#include <sstream>//创建Son构造函数时,需要手动调用父类的构造函数,用来初始化父类的数据
// r如果不手动调用,就会默认调用父类的默认构造函数,也就是啥参数都不传的Father()
//再调用自己Son的构造函数,初始化自己的数据
Son::Son(const char* name, int age, const char* game):Father(name,age)
{cout << __FUNCTION__ << endl;this->game = game;//name和age在父类里面已经初始化了,子类就不需要再初始化了
}Son::~Son()
{
}string Son::getGame()
{return game;
}//父类和子类有一个同名的成员函数,调用的时候,会先在自己的成员函数列表里面找,如果找不到,才会去父类的列表里面找
string Son::description()
{//son类继承父类,不能访问父类的私有成员// 	//stringstream ret;//ret << "name:" << name << "-年龄:" << age;//return ret.str();// 如果想用重载,但是又想访问父类的私有成员,可以将父类的私有成员改成protected,或者用父类的公有成员函数实现间接访问父类的私有成员函数stringstream ret;ret << "name:" << getName() << "-年龄:" << getAge() << ", game:" << getGame();return ret.str();
}

7.2 为什么要有protected类型的定义

  • 知识点1:类创建的对象本身,也不能直接访问私有变量
    Father fjr;
    不允许通过fjr.name 访问私有变量name
  • 知识点2: 类内部函数之间是可以直接访问自己的私有变量的
  • 知识点3: 一个类,如果希望他的成员变量可以被自己的子类直接访问,但是又不想被外部访问(也就是创建对象之后,直接用自己类创建的对象访问自己的私有变量,对应知识点1),就可以将变量定义为protected
    在这里插入图片描述
    在这里插入图片描述

7.3 子类对父类的访问权限问题 ?????

在这里插入图片描述

7.4 子类和父类之间构造函数的调用顺序

静态成员只调用一次
在这里插入图片描述
在这里插入图片描述

class M {public:M() { cout << __FUNCTION__ << endl; }
};class N {
public:N() { cout << __FUNCTION__ << endl; }
};class A {
public:A() { cout << __FUNCTION__ << endl; }
};class B:public A {
public:B() { cout << __FUNCTION__ << endl; }private:M m1;M m2;static N ms; 
};N B::ms;  //静态成员int main(void) {B b;return 0;
}

7.5 子类的析构函数调用

子类的析构函数的调用顺序正好和构造函数的调用顺序相反

7.6 子类型

(a)定义

子类具有单向传递性,C是B的子类型,B是A的子类型,则C也是A的子类型
在这里插入图片描述

(b) 子类型的作用

以下三种
在这里插入图片描述

#include <iostream>
#include "string"
#include<Windows.h>
using namespace std;class Father {
public:void play() {cout << "Father KTV sing" << endl;}
};class Son :public Father {
public:void play() {cout << "Son eat chiken" << endl;}
};//void party(Father* f1, Father* f2)
//{
//	f1->play();
//	f2->play();
//}void party(Father f1, Father f2)
{f1.play();f2.play();
}int main(void) {Father yangkang;Son yangguo;//party(&yangkang,&yangguo);party(yangkang, yangguo);  //两个调用的都是父亲的playcout << "*************************************************************" << endl;cout << " 以下三种情况的本质都是 子类的东西都是从父类继承的,父类有的子类一定有" << endl;cout << "*************************************************************" << endl;cout << "" << endl;cout << "------------父类指针指向子类对象,调用的是父类的东西--------------" << endl;//父类指针指向子类对象Father wjl;Son wsc;Father* p;p = &wsc;p->play();cout << "------------父类引用指向子类对象--------------" << endl;Father wjl_2;Son wsc_2;Father &p2 = wsc_2;p2.play();cout << "------------父类对象直接赋值给子类对象,本质是子类的东西都是从父类继承的,父类有的子类一定有-------------" << endl;Father wjl_3;Son wsc_3;wjl_3 = wsc_3;wsc_3.play();system("pause");return 0;
}

8 多重继承的使用

8.1 什么是多重继承

在这里插入图片描述

  • 知识点1:继承的声明的两个地方
    Son class 构造函数创建 的地方class Son:public Father, public Mother,以及Son的构造函数的实现
    Son::Son(const char* food, const char* game, const char* lastName, const char* firstName):Father(lastName, firstName), Mother(food)

  • 知识点2:继承多个构造函数,先调用谁的,是依次调用,谁写在前面先调用谁

  • 知识点3:子类继承多个类的时候,构造函数初始化多个父类的时候,只需要传入儿子没有的,且不需要重复传入,Son::Son(const char* food, const char* game, const char* lastName, const char* firstName):Father(lastName, firstName), Mother(food) { this->game = game; } 这个地方,父类和母亲类都有自己的const char* lastName, const char* firstName, 但是只在初始化父亲的时候传递了这两个参数

#pragma once
#include "Father.h"
#include "Mother.h"class Son:public Father, public Mother
{
public:Son(const char* food, const char* game,const char* lastName, const char* firstName);~Son();void playGame();
private:std::string game;
};#include "Son.h"
#include "string"
#include <iostream>
using namespace std;Son::Son(const char* food, const char* game,const char* lastName, const char* firstName):Father(lastName, firstName), Mother(food)
{this->game = game;
}Son::~Son()
{
}void Son::playGame()
{cout << "play game" << endl;
}
  • 知识点:1:如果子类继承的多个类有同名函数,则调用的时候需要指定调用谁 wsc.Father::dance(); 或者 wsc.Mother::dance();
#include <iostream>
#include "string"
#include<Windows.h>
using namespace std;
#include "Son.h"int main(void) {Son wsc("wang","si cong","chuan cai","CHiji");wsc.playBasketball();wsc.playGame();//父亲类和母亲类都有这个函数,子类继承了父亲和目前,会产生歧义,报错//wsc.dance();//需要限定函数或者子类自己写一个dance函数,在函数里面指定调用谁wsc.Father::dance();wsc.Mother::dance();system("pause");return 0;
}//*********************************************************
#pragma once
#include "Father.h"
#include "Mother.h"class Son:public Father, public Mother
{
public:Son(const char* food, const char* game,const char* lastName, const char* firstName);~Son();void playGame();
private:std::string game;
};#include "Son.h"
#include "string"
#include <iostream>
using namespace std;Son::Son(const char* food, const char* game,const char* lastName, const char* firstName):Father(lastName, firstName), Mother(food)
{this->game = game;
}Son::~Son()
{
}void Son::playGame()
{cout << "play game" << endl;
}
//*********************************************************
#pragma once
#include "string"class Father
{
public:Father(const char * lastName = "wu ming", const char* firstName = "wu xing");~Father();void playBasketball();void dance();//保护和私有只影响继承关系,私有的子类不能直接访问
protected:std::string lastName; std::string firstName;
};
#include <iostream>
#include "string"
#include "Father.h"
using namespace std;Father::Father(const char* lastName,const char* firstName)
{this->firstName = firstName;this->lastName = lastName;
}Father::~Father()
{}void Father::playBasketball()
{cout << "  playBasketball" << endl;
}void Father::dance()
{cout << "  霹雳舞" << endl;
}//*********************************************************
#pragma once
#include "string"class Mother
{
public:Mother(const char* food,const char* lastName = "wu ming", const char* firstName = "wu xing");~Mother();void dance();//保护和私有只影响继承关系,私有的子类不能直接访问
protected:std::string lastName;std::string firstName;std::string food;
};
#include "Mother.h"#include <iostream>
#include "string"
using namespace std;Mother::Mother(const char* food,const char* lastName, const char* firstName)
{this->firstName = firstName;this->lastName = lastName;this->food = food;
}Mother::~Mother()
{}void Mother::dance()
{cout << " dancing" << endl;
}

8.2 菱形继承存在的问题

在这里插入图片描述

  • 知识点:上面的无线座机继承了座机类和手机类,会导致歧义,同名成员函数或变量,使用的时候需要指定是哪个类的成员FixedLine::number;,按道理来说主函数设置了号码,打印号码应该是设置值,但是打印的是Tel类里面的数值
#include <iostream>
#include "string"
#include<Windows.h>
using namespace std;//电话类
class Tel {
public:Tel() {this->number = "123456";}protected:string number;
};//座机
class FixedLine :public Tel {
public:};//手机
class MpobilePhone :public Tel {};//无线座机
class WirelessTel :public FixedLine, public MpobilePhone {
public:void setNumber(const char* number) {//number 不明确,继承了2个number,FixedLine和MpobilePhone里面各继承了一个//this->number = number;this->FixedLine::number = number;}string getNumber(){return this->MpobilePhone ::number;}
};int main(void) {WirelessTel phone;phone.setNumber("1234556677");cout << phone.getNumber() << endl;system("pause");return 0;
}

8.3 解决菱形继承访问歧义问题的方法:虚基类和虚继承

  • 知识点:虚基类对本身是没有任何影响的,只是他有多个子类,为了方便后面的使用class FixedLine :virtual public Tel
#include <iostream>
#include "string"
#include<Windows.h>
using namespace std;//电话类
//此时共同的主线Tel类就是虚基类
class Tel {
public:Tel() {this->number = "123456";}protected:string number;
};//座机, 虚继承
class FixedLine :virtual public Tel {
public:};//手机
class MpobilePhone :virtual public Tel {};//无线座机
class WirelessTel :public FixedLine, public MpobilePhone {
public:void setNumber(const char* number) {//number 不明确,继承了2个number,FixedLine和MpobilePhone里面各继承了一个this->number = number;  //FixedLine和MpobilePhone改成虚基类就可以//this->FixedLine::number = number;}string getNumber(){return this->number;}
};int main(void) {WirelessTel phone;phone.setNumber("1234556677");cout << phone.getNumber() << endl;system("pause");return 0;
}

9 文本读取和写入 C++流

在这里插入图片描述

  • 文件的读写,只能用自带的,下面的类之间是继承的关系
    在这里插入图片描述

9.1 对文件进行读写

在这里插入图片描述

  • 向文件夹写东西,直接默认覆盖以前的东西
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
using namespace std;int main(void) {string name;int age;// 默认是写操作ofstream outfile; //定义了一个文件输出流对象,//使用输出流对象打开一个文件outfile.open("user.txt");  //会覆盖原来的内容while (1){cout << "请输入姓名:[ctrl+z 退出]";cin >> name;if (cin.eof()) {break;}//把输入的姓名写入wenjainoutfile << name << "\t";cout << "请输入年龄:[ctrl+z 退出]";cin >> age;//把输入的姓名写入wenjainoutfile << age << "\n";}//关闭文件outfile.close();system("pause");return 0;
}
  • 读文件
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
using namespace std;int main(void) {string name;int age;ifstream inFile;inFile.open("user.txt");while (1){if (inFile.eof()) {break;}inFile >> name;cout << name << "\t";inFile >> age;cout << age << endl;}inFile.close();system("pause");return 0;
}

9.2 对二进制文件的读写

在这里插入图片描述

  • 写二进制文件
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
using namespace std;int main(void) {string name;int age;ofstream outFile;outFile.open("user.dat", ios::out | ios::trunc| ios::binary);while (1){cout << "请输入姓名:[ctrl+z 退出]";cin >> name;outFile << name << "\t";if (cin.eof()) {break;}cout << "请输入年龄:[ctrl+z 退出]";cin >> age;//outFile << age << endl;  会转成字符串,然后存在二进制文件里面,是错的outFile.write((char*)&age, sizeof(age));}outFile.close();system("pause");return 0;
}
  • 读二进制文件
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
using namespace std;int main(void) {string name;int age;ifstream inFile;inFile.open("user.dat", ios::in | ios::binary);while (1){inFile >> name;if (inFile.eof()) {break;}cout << name << "\t";//文件里面的字符\t,不会自动跳过,需要手动char tmp;inFile.read(&tmp, sizeof(tmp));inFile.read((char*)&age,sizeof(age));cout << age << endl;}inFile.close();system("pause");return 0;
}

9.3 按照置钉的格式读写文件

  • 写文件

知识点: 利用利用stringstream来对数据进行格式化

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;int main(void) {string name;int age;ofstream outFile;outFile.open("user.txt");while (1){cout << "请输入姓名:【ctrl+z 退出】:";cin >> name;if (cin.eof()){break;}cout << "请输入年龄:【ctrl+z 退出】:";cin >> age;//利用stringstream来对数据进行格式化stringstream s;s << "姓名: " << name << "\t\t年龄" << age << endl;outFile << s.str();}outFile.close();system("pause");return 0;
}

在这里插入图片描述

  • 读文件
    c语言按照指定格式读文件方式
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;int main(void) {char name[32];int age;ifstream inFile;string line;inFile.open("user.txt");while (1){getline(inFile, line);if (inFile.eof()){break;}sscanf_s(line.c_str(), "姓名:%s 年龄%d", name, sizeof(name), &age);cout << "姓名: " << name << "\t\t\t年龄" << age << endl;}inFile.close();system("pause");return 0;
}

10 位图算法

在这里插入图片描述
在这里插入图片描述
一个字节是8位,所谓快速算法,牺牲空间。如果最大数到21,那就需要用3个字节,28个位
在这里插入图片描述

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;void init(char* data, int len)
{//这里假设一个需求,//假设能被3整除的数都在这个集合中,假设有40亿个数据,这里是为了测试算法效果unsigned int n = len * 8;for (unsigned int i = 0; i <n; i++){if (i % 3 == 0){char* p = data + i / 8;*p = *p | (1 << (i % 8));}}
}bool check(char* data, int len,int value)
{//定位到指定的字节char* p = data + value / 8;bool ret = *p & (1 << (value % 8));//判断这个字节中指定的位是否为1return ret;
}int main(void) {//分配一块足够的空间来存放位图unsigned int n = 4000000000;int len = n / 8 + 1;char* data = (char*)malloc(len);memset(data, 0, len);  //清0//装载数据集合init(data,len);while (1){printf("输入要检测是数【输入-1退出】:");int value;scanf_s("%d", &value);if (value == -1){break;}if (check(data, len, value)){printf("%d 数据在集合中\n",value);}else{printf("%d 数据不在集合中\n", value);}}return 0;
}

11 文件流的定位 读取指定位置的信息

在这里插入图片描述

11.1 - 实现:读取当前文件的最后50个字节

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;
int main(void) {ifstream infile;string line;infile.open("test.cpp");if (!infile.is_open()) {return 1;}infile.seekg(-50, infile.end);while (!infile.eof()){getline(infile, line);cout << line << endl;}infile.close();system("pause");return 0;
}

11.2 tellg函数返回输入流当前的位置,也即返回距离文件起始位置的偏移量

  • 案例:获取当前文件的长度。思路,偏移量指到文件尾即可
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;//定义一个函数用来返回指定文件的大小
long long getSize(const char* fileName)
{ifstream infile;infile.open(fileName);if (!infile.is_open()) {return 0;}infile.seekg(0, infile.end);long long ret = infile.tellg();infile.close();return ret; // 返回当前位置的偏移量
}int main(void) {cout << getSize("test.txt");   //返回的是字节system("pause");return 0;
}

11.3 seekp ,向指定位置写入内容

在这里插入图片描述

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
using namespace std;int main(void) {ofstream outfile;outfile.open("test1.txt");if (!outfile.is_open()){return 1;}outfile << "12345678";   outfile.seekp(4, outfile.beg);outfile << "ABC";outfile.close();system("pause");return 0;
}

在这里插入图片描述

11.4 文件流的状态检查

在这里插入图片描述

12 友元

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/183af8a1f25d4d9696e4295a267cbdc3.png #pic_center =300x)
在这里插入图片描述
在这里插入图片描述

12.1 全局函数做为友元函数

需求:计算机本身不能自己给自己升级,从外部调用一个升级函数对当前计算机进行升级

#pragma once
#include "string"using namespace std;class Compute
{
public:Compute();string description();//把这个全局函数声明为当前类的友元函数,写在public和private里面都是可以的,效果没有区别friend void upgrade(Compute * compute);
private:string cpu;
};——————————————————————————————————————————————*#include "Compute.h"
#include <sstream>Compute::Compute()
{this->cpu = "i7";
}string Compute::description()
{stringstream ret;ret << "CPU = " << cpu;return ret.str();
}

主函数

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
#include "Compute.h"using namespace std;void upgrade(Compute* compute)
{compute->cpu = "i9";   //外部不能直接访问类的私有成员,定义成友元函数就可以了
}int main(void) {Compute compute;cout << compute.description() << endl;upgrade(&compute);cout << compute.description() << endl;system("pause");return 0;
}

12.2 一个类的成员函数做为另一个类的友元函数

#pragma once
#include "string"
#include "ComputerService.h"using namespace std;class ComputerService;class Compute
{
public:Compute();string description();private:string cpu;friend void ComputerService::upgrade(Compute* compute);
};************************
#include "Compute.h"
#include <sstream>
#include "ComputerService.h"Compute::Compute()
{this->cpu = "i7";
}string Compute::description()
{stringstream ret;ret << "CPU = " << cpu;return ret.str();
}
#pragma once
#include "Compute.h"
class Compute;class ComputerService
{
public:ComputerService();void upgrade(Compute* compute);
};***************************
#include "ComputerService.h"
#include "Compute.h"ComputerService::ComputerService()
{
}void ComputerService::upgrade(Compute* compute)
{compute->cpu = "i9";
}
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
#include "Compute.h"
#include "ComputerService.h"
using namespace std;int main(void) {Compute compute;ComputerService service;cout << compute.description() << endl;service.upgrade(&compute);cout << compute.description() << endl;system("pause");return 0;
}

12.3 友元类

如果只需要用到另一个类的某一个函数,并且要求外部这个函数可以访问当前类的私有的东西,那就可以使用用友元函数
但是如果需要使用到另一个类的很多东西,并且要求这些外部的东西可以访问当前类的私有成员,那就可以用友元类
在这里插入图片描述

#pragma once
#include "string"
#include "ComputerService.h"using namespace std;class ComputerService;class Compute
{
public:Compute();string description();private:string cpu;//无论在private里面声明还是在public声明都一样friend class ComputerService;
};&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
#include "Compute.h"
#include <sstream>
#include "ComputerService.h"Compute::Compute()
{this->cpu = "i7";
}string Compute::description()
{stringstream ret;ret << "CPU = " << cpu;return ret.str();
}
#pragma once
#include "Compute.h"
class Compute;class ComputerService
{
public:ComputerService();void upgrade(Compute* compute);void clean(Compute* compute);void kill(Compute* compute);
};
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
#include "ComputerService.h"
#include "Compute.h"
#include <iostream>
using namespace std;
ComputerService::ComputerService()
{
}
void ComputerService::upgrade(Compute* compute)
{compute->cpu = "i9";
}void ComputerService::clean(Compute* compute)
{cout << "clear compute : "  << compute->cpu  << " ...." << endl;
}void ComputerService::kill(Compute* compute)
{cout << "kill verus compute : " << compute->cpu << " ...." << endl;
}
int main(void) {Compute compute;ComputerService service;cout << compute.description() << endl;service.upgrade(&compute);service.kill(&compute);service.clean(&compute);cout << compute.description() << endl;system("pause");return 0;
}

13 运算符重载

13.1 使用成员函数实验运算符重载

在这里插入图片描述

main函数

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
#include "Cow.h"
#include "Goat.h"
#include "Pork.h"using namespace std;
int main(void) {Cow c1(100);Cow c2(200);Pork p = c1 + c2; //此时调用的是c1.operator+(c2)cout << p.description() << endl;Goat g1(100);Pork p2 = c1 + g1;cout << p2.description() << endl;system("pause");return 0;
}
#pragma onceclass Pork;
class Goat;class Cow
{
public:Cow(int weight);//使用运算符重载实现:一头牛+一只羊 = ?Pork operator+(const Goat& goat); //牛+羊 = ?猪肉Pork operator+(const Cow& cow);   //牛+羊= ?猪肉private:int weight = 0;};
----------------------------------------
#include "Cow.h"
#include "Goat.h"
#include "Pork.h"Cow::Cow(int weight)
{this->weight = weight;
}Pork Cow::operator+(const Goat& goat)
{int tmp = this->weight*2 + goat.getWeight() * 3;return Pork(tmp);
}Pork Cow::operator+(const Cow& cow)
{int tmp = (this->weight + cow.weight) * 2;return Pork(tmp);
}//一斤牛肉 = 两斤猪肉
//一斤羊肉 = 三斤猪肉
#pragma once
#include <string>
using namespace std;class Pork
{
public:Pork(int weight = 0);string description();private:int weight = 0;};
----------------------------------------
#pragma once
#include <string>
using namespace std;class Pork
{
public:Pork(int weight = 0);string description();private:int weight = 0;};
#pragma once
class Goat
{
public:Goat(int weight = 0);int getWeight() const;
private:int weight = 0;};
----------------------------------------
#include "Goat.h"Goat::Goat(int weight)
{this->weight = weight;
}int Goat::getWeight() const
{return weight;
}

13.2 使用非成员函数实现运算符重载,非内部函数,也即使用友元函数,

在13.1的基础上修改了以下两个地方

main

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>
#include "Cow.h"
#include "Goat.h"
#include "Pork.h"using namespace std;Pork operator+(const Cow& cow1, const Cow& cow2)
{int tmp = (cow1.weight + cow2.weight)*2;return Pork(tmp);
}Pork operator+(const Cow& cow, const Goat& goat)
{//goat.getWeight(), 因为没有声明羊是牛的友元函数,所以无法直接访问私有成员//cow可以直接访问weight 是因为当前外部函数被定义在了Cow类里面int tmp = cow.weight * 2 + goat.getWeight() * 3;return Pork(tmp);
}int main(void) {Cow c1(100);Cow c2(200);Pork p = c1 + c2; //此时调用的是c1.operator+(c2)cout << p.description() << endl;Goat g1(100);Pork p2 = c1 + g1;cout << p2.description() << endl;system("pause");return 0;
}

Cow.h

#pragma onceclass Pork;
class Goat;class Cow
{
public:Cow(int weight);friend Pork operator+(const Cow& cow1, const Cow& cow2);friend Pork operator+(const Cow& cow, const Goat& goat);
private:int weight = 0;};

13.3 什么时候选择非成员函数(友元函数),什么时候选择成员函数来实现重载

在这里插入图片描述

  • 核心知识点:使用成员函数来实现重载的时候,Cow c2 = c1+100; 等价于调用c1.operator+(100),如果此时对换顺序,Cow c3 = 200 + c1; 不允许,因为不存在200.operator+(c1),这种情况必须使用友元函数来做
  • 使用成员函数实现Cow c2 = c1+100; ,主要代码如下:
class Cow
{
public:Cow(int weight);**************************Cow operator+(int n);**************************
private:int weight = 0;
};main主函数:Cow c1(100);Cow c2 = c1+100; // 等价于调用c1.operator+(100)
  • 使用友元函数实现200.operator+(c1),核心代码如下
class Cow
{
public:Cow(int weight);**************************friend Cow operator+(int n,const Cow& cow1);**************************
private:int weight = 0;
};main主函数:
Cow operator+(int n, const Cow& cow1)
{int temp = cow1.weight + n;return Cow(temp);
}
。。。。Cow c1(100);Cow c3 = 200 + c1;

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

13.4 重载 = ,赋值运算符

  • 类的重载,实现类的赋值运算,在类里面声明Boy& operator=(const Boy& boy);

class Boy

#pragma once
#include <iostream>
class Boy
{
public:Boy(const char* name = NULL, int age = 0, int salary = 0, int darkHorse = 0);~Boy();std::string description();//重载Boy& operator=(const Boy& boy);
private:char* name;int age;int salary;int darkHorse;unsigned int id;static int LAST_ID;
};************************** 	**************************#include "Boy.h"
#include <sstream>
#include <string>
using namespace std;
int Boy::LAST_ID = 0;Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!name) {name = "未命名";}this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = age;this->salary = salary;this->darkHorse = darkHorse;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name){delete name;}
}Boy& Boy::operator=(const Boy& boy)
{// TODO: 在此处插入 return 语句if (name){delete name; //释放原来的内存}name = new char[strlen(boy.name) + 1];strcpy_s(name, strlen(boy.name) + 1, boy.name);this->age = boy.age;this->salary = boy.salary;this->darkHorse = boy.darkHorse;//this->id = ++LAST_ID;return *this;
}std::string Boy::description()
{stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t age:" << age << "\t salary :" << salary << "\t Horse factor" << darkHorse << endl;return ret.str();
}

mian

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>#include "Boy.h"using namespace std;int main(void) {Boy boy1("Rock", 38, 58000, 10);Boy boy2, boy3;cout << boy1.description() << endl;cout << boy2.description() << endl;cout << boy3.description() << endl;boy3 = boy2 = boy1;cout << " ------------" << endl;cout << boy1.description() << endl;cout << boy2.description() << endl;cout << boy3.description() << endl;system("pause");return 0;
}

在这里插入图片描述

13.5 重载 >, < == ,关系运算符重载

#pragma once
#include <iostream>
class Boy
{
public:Boy(const char* name = NULL, int age = 0, int salary = 0, int darkHorse = 0);~Boy();std::string description();//重载Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);private:char* name;int age;int salary;int darkHorse;unsigned int id;static int LAST_ID;int power() const; //综合能力值
};
************************** 	**************************
#include "Boy.h"
#include <sstream>
#include <string>
using namespace std;
int Boy::LAST_ID = 0;Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!name) {name = "未命名";}this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = age;this->salary = salary;this->darkHorse = darkHorse;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name){delete name;}
}Boy& Boy::operator=(const Boy& boy)
{// TODO: 在此处插入 return 语句if (name){delete name; //释放原来的内存}name = new char[strlen(boy.name) + 1];strcpy_s(name, strlen(boy.name) + 1, boy.name);this->age = boy.age;this->salary = boy.salary;this->darkHorse = boy.darkHorse;//this->id = ++LAST_ID;return *this;
}std::string Boy::description()
{stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t age:" << age << "\t salary :" << salary << "\t Horse factor" << darkHorse << endl;return ret.str();
}bool Boy::operator>(const Boy& boy)
{if (power() > boy.power()){return true;}else{return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()){return true;}else{return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()){return true;}else{return false;}
}int Boy::power() const
{//设置比较规则,薪资 *黑马系数 + (100 -age)*1000;int ret = salary * darkHorse + (100 - age) * 1000;return ret;
}

main

using namespace std;
int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);if (boy1 > boy2) // ===  》 boy1.operatr>boy2{cout << "选择boy1" << endl;}else if (boy1 < boy2){cout << "选择boy2" << endl;}else{cout << "差不多" << endl;}system("pause");return 0;
}

13.6 重载[ ],下标运算符重载

功能:直接通过字符串获取对应的值
在这里插入图片描述

声明

int operator[](string index);
int Boy::operator[](string index)
{if (index == AGE_KEY){return age;}else if (index == SALARY_KEY){return salary;}else if (index == DARKHOURSE_KEY){return darkHorse;}else if (index == POWER_KEY){return power();}else{return -1;}
}
#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>#include "Boy.h"
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARKHOURSE_KEY "darkHorse"
#define POWER_KEY "power"
using namespace std;int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);cout << "boy1[age] = " << boy1[AGE_KEY] <<",boy1[salary] = " << boy1[SALARY_KEY] <<",boy1[darkHorse] = " << boy1[DARKHOURSE_KEY] <<",boy1[power] = " << boy1[POWER_KEY] << endl;system("pause");return 0;
}

13.7 >> ,<<,输入输出运算符重载

  • 成员函数实现输出运算符重载 ostream& operator<<(ostream& os) const;
  • 友元函数实现输出运算符重载friend ostream& operator <<(ostream& os, const Boy& boy);
  • 友元函数实现输入运算符重载friend istream& operator >>(istream& is, Boy& boy);

boy类

#pragma once
#include <iostream>
#include "string"
using namespace std;
class Boy
{
public:Boy(const char* name = NULL, int age = 0, int salary = 0, int darkHorse = 0);~Boy();std::string description();//定义返回类型为ostream是为了可以连续调用ostream& operator<<(ostream& os) const;//调用的时候 boy1 << cout;,这种方式不符合调用习惯friend ostream& operator <<(ostream& os, const Boy& boy);friend istream& operator >>(istream& is, Boy& boy);
private:char* name;int age;int salary;int darkHorse;unsigned int id;static int LAST_ID;int power() const; //综合能力值
};************************** 	**************************
#include "Boy.h"
#include <sstream>
#include <string>
using namespace std;
int Boy::LAST_ID = 0;
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARKHOURSE_KEY "darkHorse"
#define POWER_KEY "power"
Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!name) {name = "未命名";}this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = age;this->salary = salary;this->darkHorse = darkHorse;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name){delete name;}
}std::string Boy::description()
{stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t age:" << age << "\t salary :" << salary << "\t Horse factor" << darkHorse << endl;return ret.str();
}ostream& Boy::operator<<(ostream& os) const
{// TODO: 在此处插入 return 语句os << "ID:" << id << "\t姓名:" << name << "\t age:" << age << "\t salary :" << salary << "\t Horse factor" << darkHorse << endl;return os;
}int Boy::power() const
{//设置比较规则,薪资 *黑马系数 + (100 -age)*1000;int ret = salary * darkHorse + (100 - age) * 1000;return ret;
}

main

#include <iostream>
#include "string"
#include<Windows.h>
#include <fstream>
#include  <sstream>#include "Boy.h"
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARKHOURSE_KEY "darkHorse"
#define POWER_KEY "power"
using namespace std;ostream& operator<<(ostream& os, const Boy& boy)
{os << "ID:" << boy.id << "\t姓名:" << boy.name << "\t age:" << boy.age << "\t salary :" << boy.salary << "\t Horse factor" << boy.darkHorse << endl;return os;
}istream& operator >>(istream& is, Boy& boy)
{is >> boy.name >> boy.age >> boy.salary >> boy.darkHorse;return is;
}int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);//cout << boy1; 不对,因为opetator<<函数是boy的成员函数  // ostream& operator<<(ostream& os) const;boy1 << cout; //boy1.opetator<<(cout)cout << boy1 << endl << boy2 << endl;cin >> boy1;cout << boy1;system("pause");return 0;
}

13.8 普通类型转换成类类型

希望达到的效果
在这里插入图片描述

class Boy
{
public:Boy(const char* name, int age, int salary, int darkHorse);~Boy();Boy(int salary);Boy(const char* name);。。。
private:。。。
***********************************************
Boy::Boy(int salary)
{const char* name = "未命名";this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = 0;this->salary = salary;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::Boy(const char* name)
{this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = 0;this->salary = 0;this->darkHorse = 0;this->id = ++LAST_ID;
}
int main(void) {Boy boy1 = 58000;Boy boy2 = "Jack";cout << boy1 << endl << boy2 << endl
}

在这里插入图片描述

13.9 类类型 转成 普通类型

实现效果:想用int power = boy1; 直接替换int power = boy1.power();,直接获取boy类的竞争力power
在这里插入图片描述

class Boy
{
public:。。。//类型运算符重载,不需要返回值operator int() const;operator char* () const;private:。。。
};
***********************************************
Boy::operator int() const
{return power();
}Boy::operator char* () const
{return name;
}
int main(void) {Boy boy1("Rock",28,58000,5);int power = boy1;char* name = boy1;cout << boy1.description() << endl;cout << power << endl;cout << name << endl;system("pause");return 0;
}

13.10 类类型A 转成 类类型B

在这里插入图片描述
例如下面的案例将boy类的参数直接复制给man类
除了原本的Man类里面的构造函数,再定义一个构造函数 Man(Boy& boy);

	Man(const char* name, int age, int salary);Man(Boy& boy);

函数的实现

Man::Man( Boy& boy)
{int len = strlen(boy.getName()) + 1;this->name = new char[len];//cout << boy.getName();strcpy_s(this->name, len, boy.getName());this->age = boy.getAge();this->salary = boy.getSalary();
}

那么主函数里面就可以直接进行赋值操作了

	Boy boy1("Rock",28,58000,5);Man man = boy1;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/55883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络803-(4)网络层

目录 1.虚电路服务 虚电路是逻辑连接 2.数据报服务 3.虚电路服务与数据报服务的对比 二.虚拟互连网络-IP网 1.网络通信问题 2.中间设备 3.网络互连使用路由器 三.分类的 IP 地址 1. IP 地址及其表示方法 2.IP 地址的编址方法 3.分类 IP 地址 &#xff08;1&#x…

LabVIEW中的非阻塞定时器

在LabVIEW编程中&#xff0c;通常需要在某些任务执行过程中进行非阻塞的延时操作。例如&#xff0c;显示某条信息一段时间&#xff0c;同时继续执行其他任务&#xff0c;并在延时时间结束后停止显示该信息。这类需求通常用于处理优先级不同的信息显示&#xff0c;如错误信息需要…

【Arduino IDE安装】Arduino IDE的简介和安装详情

目录 &#x1f31e;1. Arduino IDE概述 &#x1f31e;2. Arduino IDE安装详情 &#x1f30d;2.1 获取安装包 &#x1f30d;2.2 安装详情 &#x1f30d;2.3 配置中文 &#x1f30d;2.4 其他配置 &#x1f31e;1. Arduino IDE概述 Arduino IDE&#xff08;Integrated Deve…

Jupyter的使用分享

文章目录 碎碎念安装方法1.安装Anaconda方法2.通过库的安装方式 启动使用教程1.指定目录打开2.启动后的简单使用 小结 碎碎念 前情提示 之前与许多小伙伴交流的时候&#xff0c;发现大家对于pycharm更容易上手&#xff08;可能是比较好设置中文的原因&#xff09;&#xff0c;在…

算法: 前缀和题目练习

文章目录 前缀和题目练习前缀和二维前缀和寻找数组的中心下标除自身以外数组的乘积和为 K 的子数组和可被 K 整除的子数组连续数组矩阵区域和 前缀和题目练习 前缀和 自己写出来了~ 坑: 数据太大,要用long. import java.util.Scanner;public class Main {public static voi…

【element-tiptap】如何引进系统中的字体?

源码地址&#xff1a; https://github.com/Leecason/element-tiptap 源码中给出的字体如下 可以看到&#xff0c;咱们日常需要的黑体、微软雅黑等都没有&#xff0c;所以这篇文章来探索一下怎么加字体。 另外呢&#xff0c;肯定有小伙伴发现&#xff0c;这个按钮点击的时候&am…

IDEA 配置 Git 详解

本文将介绍在IntelliJ IDEA 中如何配置Git 没有安装配置 Git 的可以参考我的这篇文章&#xff1a;安装配置 Git 一、操作环境及准备 1.win 10 2.已安装且配置了Git 3.有Gitee账户 4.安装了IntelliJ IDEA 2023.2.1 5.全程联网 二、配置步骤 2.1 配置git 1.采用全局设置&…

C++继承与菱形继承(一文了解全部继承相关基础知识和面试点!)

目的减少重复代码冗余 Class 子类(派生类) &#xff1a; 继承方式 父类&#xff08;基类&#xff09; 继承方式共有三种&#xff1a;公共、保护、私有 父类的私有成员private无论哪种继承方式都不可以被子类使用 保护protected权限的内容在类内是可以访问&#xff0c;但是在…

息肉检测数据集 yolov5 yolov8适用于目标检测训练已经调整为yolo格式可直接训练yolo网络

息肉检测数据集 yolov5 yolov8格式 息肉检测数据集介绍 数据集概述 名称&#xff1a;息肉检测数据集&#xff08;基于某公开的分割数据集调整&#xff09;用途&#xff1a;适用于目标检测任务&#xff0c;特别是内窥镜图像中的息肉检测格式&#xff1a;YOLO格式&#xff08;边…

【3dgs】总结3DGS与NeRF如何重塑SLAM24年4月最新进展

【3dgs】总结3DGS与NeRF如何重塑SLAM&#xff01; 1. 摘要2. 简洁3. 背景3.1 Existing SLAM Surveys3.2 progress in Radiance Field Theory3.3.1 NeRF3.3.2 3dgs3.4 数据集 4 数据集4.1 SLAM3.1 RGB-D SLAM方法3.1.1 基于NeRF风格的RGB-D SLAM3.1.2 基于3DGS风格的 RGB-D SLAM…

React(一) 认识React、熟悉类组件、JSX书写规范、嵌入变量表达式、绑定属性

文章目录 一、初始React1. React的基本认识2. Hello案例2.1 三个依赖2.2 渲染页面2.3 hello案例完整代码 二、类组件1. 封装类组件2. 组件里的数据3. 组件里的函数 (重点)4. 案例练习(1) 展示电影列表 三、JSX语法1. 认识JSX2. JSX书写规范及注释3. JSX嵌入变量作为子元素4. JS…

遍历有向图链路(DFS算法)- 优化版

在上一节基础上&#xff0c;去除了节点的pre集合&#xff0c;只保留节点next的结合&#xff0c;对数据模型进行了优化&#xff0c;实现思想做了优化。 有向图示例&#xff1a; 基本思路 构建有向图数据模型校验有向图不能出现回路&#xff0c;即当前节点不能出现在历史链路中首…

连续点击三次用户

有用户点击日志记录表 t2_click_log&#xff0c;包含user_id(用户ID),click_time(点击时间)&#xff0c;请查询出连续点击三次的用户数&#xff0c; 连续点击三次&#xff1a;指点击记录中同一用户连续点击&#xff0c;中间无其他用户点击&#xff1b; CREATE TABLE t2_click…

Unity实现自定义图集(三)

以下内容是根据Unity 2020.1.0f1版本进行编写的   1、实现编辑器模式下进游戏前Pack全部自定义图集 同Unity的图集一样,Unity的编辑器模式会在进游戏前把全部的SpriteAtlas都打一次图集,如图: 我们也实现这样的效果。 首先需要获取全部的图集路径。因为目前使用的是以.…

【数据结构】6道经典链表面试题

目录 1.返回倒数第K个节点【链接】 ​代码实现 2.链表的回文结构【链接】 代码实现 3.相交链表【链接】 代码实现 4.判断链表中是否有环【链接】 代码实现 常见问题解析 5.寻找环的入口点【链接】 代码实现1 ​代码实现2 6.随机链表的复制【链接】 代码实现 1.…

如何进行数据中心负载测试的自动化?

数据中心负载测试的自动化是一种通过使用软件工具和脚本来模拟大量用户访问数据中心的过程&#xff0c;以评估其性能、稳定性和可扩展性的方法。以下是进行数据中心负载测试自动化的一些建议&#xff1a; 市场上有许多负载测试工具可供选择&#xff0c;如LoadRunner、JMeter、…

字节跳动青训营开始报名了!

关于青训营&#xff1a; 青训营是字节跳动技术团队发起的技术系列培训 &人才选拔项目;面向高校在校生&#xff0c;旨在培养优秀且具有职业竞争力的开发工程师。 本次技术训练营由掘金联合豆包MarsCode 团队主办课程包含前端、后端和 A 方向&#xff0c;在这个飞速发…

盲拍合约:让竞拍更公平与神秘的创新解决方案

目录 前言 一、盲拍合约是什么&#xff1f; 二、盲拍合约工作原理 1、合约创建与初始化 2、用户出价&#xff08;Bid&#xff09; 3、出价结束 4、披露出价&#xff08;Reveal&#xff09; 5、处理最高出价 6、结束拍卖 7、退款与提款 三、解析盲拍合约代码…

adum1201数字隔离器中文资料与应用

ADuM1201是ADI公司推出的一款数字隔离器&#xff0c;其典型应用有工业自动化、通讯电源管理、医疗设备以及汽车等领域。本文将对ADuM1201数字隔离器进行详细的介绍和应用分析&#xff0c;以帮助读者更好地了解和使用该产品。 一、ADuM1201数字隔离器概述 1、基本参数 ADuM120…

达梦DBLINK访问ORACLE配置方法

目录 1、概述 2、测试环境 3、语法简介 4、配置访问DM的DBLINK 5、配置访问ORACLE的DBLINK 5.1 通过OCI配置 5.2 通过ODBC配置 1、概述 本文介绍了达梦DBLINK的配置方法。有3部分内容&#xff0c;1&#xff09;达梦访问到达梦的配置方法&#xff1b;2&#xff09;通过OC…