前期知识准备
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:
//声明方式1
Cpu cpu; //如果声明用#include "Cpu.h",这里定义了一个对象,那就会需要自动调用它的构造函数,因此必须要包含头文件
//声明方式2,下面是定义了一个指针,还没有创建对象,指针可以指向任何东西,所以不需要包含头文件
//Cpu *cpu; //要用class Cpu声明;
int hardDisk; //硬盘,单位 G
int 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); 对成员函数对象初始化的方式2
this->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; //硬盘,单位 G
int memory; // 内存
};
Computer.cpp
#include "Computer.h"
Computer::Computer(const char* cpuBrand, const char* cpuVersion,
int hardDisk, int memory)
{
this->cpu = new Cpu(cpuBrand, cpuVersion); //对成员函数对象初始化的方式2
this->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; //硬盘,单位 G
int memory; // 内存
};
#include "Computer.h"
Computer::Computer(const char* cpuBrand, const char* cpuVersion,
int hardDisk, int memory)
{
this->cpu = new Cpu(cpuBrand, cpuVersion); //对成员函数对象初始化的方式2
this->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();
//如果成员函数不会改变你的传入的变量,最好加个const
int 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); //两个调用的都是父亲的play
cout << "*************************************************************" << 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;
}
//把输入的姓名写入wenjain
outfile << name << "\t";
cout << "请输入年龄:[ctrl+z 退出]";
cin >> age;
//把输入的姓名写入wenjain
outfile << 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));
//判断这个字节中指定的位是否为1
return 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 once
class 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 once
class 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;