提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
假期即将开始,首先快速复习c++
一、命名空间
作用:防止变量或函数等重名,引起访问不明确。
//命名空间
#include<stdio.h>
#include<cstdio>
namespace Pointer1 {
void print() {
printf("你好");
}
}
namespace Pointer2 {
void print() {
printf("hello");
}
}
void print() {
printf("world");
}
int main() {
print();
Pointer1::print();
Pointer2::print();
return 0;
}
usingname space pointer;可以让下面可以使用命名空间中的所有内容。
使用print函数使用::print();的方法。
std::cout<<std::endl;
endl换行并且清空缓冲区。
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
二、引用类型
目的是尽量少的指针
#include<iostream>
using namespace std;
int main(){
int a = 100;
int& b = a;//引用类型,b是a,a就是b
cout << &b << " " << &a << endl;
return 0;
}
特点:
- 引用被创建的同时就必须进行初始化,而指针可以在任何时候进行初始化。
- 不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
- 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
//实现一个函数交换两个变量
#include<iostream>
using namespace std;
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
void swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
三.函数重载
- 相同声明域下的函数名相同但是参数列表不同(类型和个数不完全相同)
- 只有返回值类型不同不算函数重载
- 返回值类型需要相同
//实现一个函数交换两个变量
#include<iostream>
using namespace std;
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
void swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
void swap(double& a, double& b) {
double t = a;
a = b;
b = t;
}
类
类和结构体目前学习阶段认为几乎无区别,但缺省权限不同,class是私有的而struct是共有的。
#include<iostream>
using namespace std;
class Student {
public:
int age;//成员变量(属性)
int getAge() {//成员函数(方法)
return age;
}
};
类和对象
- 类:人类 动物类 植物类
- 对象: 家里的狗:大黄。。。
访问修饰符
- private:私有权限的成员变量和成员函数,只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问。
- protected:可以被该类中的函数、子类的函数、以及其友园函数访问,但不能被该类对象访问
- public:公有权限的成员变量和成员函数,可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问。
#include<iostream>
using namespace std;
class Student {
private:
int age;//成员变量(属性)
public:
int getAge() {//成员函数(方法)
return age;
}
void setAge(int a) {
if (a <= 0 || a > 100) {
cout << "请输入正确年龄" << endl;
return;
}
age = a;
}
};
int main() {
Student s;
s.setAge(30);
cout << s.getAge() << endl;
return 0;
}
构造函数
- 构造函数是类的一种特殊成员函数,一般情况下,构造函数时专门用于初始化对成员变量的,所以最好不要在构造函数中进行与对象初始化无关的操作。
- 构造函数的函数名一定与类的名称完全相同,而且没有返回值(不是说返回值时void或者int而是说不允许指定返回值)。
- 默认存在
#include<iostream>
using namespace std;
class Student {
private:
int age;//成员变量(属性)
public:
Student() {
age = 1;
}
Student(int a) {
age = a;
}
int getAge() {//成员函数(方法)
return age;
}
void growUp() {
age++;
}
void setAge(int a) {
if (a <= 0 || a > 100) {
cout << "请输入正确年龄" << endl;
return;
}
age = a;
}
};
int main() {
Student s;
s.growUp();
cout << s.getAge() << endl;
Student s1(1);
s1.growUp();
coutn << s1.getAge() << endl;
return 0;
}
析构函数
- 对象销毁的时候调用析构函数
- 默认存在
- 不支持函数重载
#include<iostream>
using namespace std;
class Student {
private:
int age;//成员变量(属性)
public:
Student() {
age = 1;
}
Student(int a) {
age = a;
}
~Student() {//析构函数
cout << "game over" << endl;
}
int getAge() {//成员函数(方法)
return age;
}
void growUp() {
age++;
}
void setAge(int a) {
if (a <= 0 || a > 100) {
cout << "请输入正确年龄" << endl;
return;
}
age = a;
}
};
int main() {
Student s;
s.growUp();
cout << s.getAge() << endl;
return 0;
}
this
- 区分成员变量和局部变量
- this代表调用当前函数的对象的地址常量
#include<iostream>
using namespace std;
class Student {
private:
int age;//成员变量(属性)
public:
Student() {
age = 1;
}
Student(int age) {
this->age = age;
}
~Student() {//析构函数
cout << "game over" << endl;
}
int getAge() {//成员函数(方法)
return age;
}
void growUp() {
age++;
}
void setAge(int a) {
if (a <= 0 || a > 100) {
cout << "请输入正确年龄" << endl;
return;
}
age = a;
}
};
int main() {
Student s;
s.growUp();
cout << s.getAge() << endl;
return 0;
}
拷贝构造函数
用途:通过一个对象复制出另一个对象
拷贝构造函数默认存在,拷贝构造函数和构造函数时重载的关系。
声明:
//默认的拷贝构造函数
//拷贝构造函数
class Student {
private:
int age;
int weight;
public:
Student() {
age = 1;
weight = 8;
}
//拷贝构造函数,默认存在
Student(const Student& rgh) {
this->age = rgh.age;
this->weight = rgh.weight;
}
int getAge() {
return age;
}
int getWeight() {
return weight;
}
};
调用拷贝构造函数
- 对象需要通过一个对象进行初始化
//拷贝构造函数
#include<iostream>
using namespace std;
class Student {
private:
int age;
int weight;
public:
Student() {
age = 1;
weight = 8;
}
//拷贝构造函数,默认存在
Student(const Student& rgh) {
this->age = rgh.age;
this->weight = rgh.weight;
}
int getAge() {
return age;
}
int getWeight() {
return weight;
}
};
int main() {
Student s;
Student s2 = s;
cout << s.getAge() << " " << s.getWeight() << endl;
cout << s2.getAge() << " " << s2.getWeight() << endl;
}
- 对象以值传递的方式传入函数参数
void printStudent(Student s2){
cout<<s2.getAge()<<" "<<s2.getWeight()<<endl;
int main(){
Student s;
printStudent(s);
return 0;
}
- 对象以值的传递方式从函数返回
Student getStudent(){
Student s;
return s;
}
int main(){
Student s2 = getStudent();
}
return一个对象的时候会执行拷贝构造函数,因为return一个值的时候会把这个值重新复制到一个地方(临时对象),如果将这个函数的返回值赋值给一个对象,编译器会进行优化,虽然执行了两次拷贝构造,但是会被优化为一次。
student s = getStudent();
深拷贝、浅拷贝
- 浅拷贝
说白了就是普普通通的值传递,传递指针之后并不会给那片区域开辟新的空间。
//拷贝构造函数
#include<iostream>
using namespace std;
class Student {
private:
int age;
int weight;
char* name;
public:
Student() {
age = 1;
weight = 8;
name = (char*)malloc(12);
strcpy(name, "xiaoming");
}
~Student() {
free(this->name);
}
//拷贝构造函数,默认存在
Student(const Student& rgh) {
this->age = rgh.age;
this->weight = rgh.weight;
this->name = rgh.name;
}
int getAge() {
return age;
}
int getWeight() {
return weight;
}
char* getName() {
return name;
}
};
int main() {
Student s;
Student s2 = s;
cout << s.getAge() << " " << s.getWeight() << endl;
cout << s2.getAge() << " " << s2.getWeight() << endl;
return 0;
}
- 深拷贝
//拷贝构造函数
#include<iostream>
using namespace std;
class Student {
private:
int age;
int weight;
char* name;
public:
Student() {
age = 1;
weight = 8;
name = (char*)malloc(12);
strcpy(name, "xiaoming");
}
~Student() {
free(this->name);
}
//拷贝构造函数,默认存在
Student(const Student& rgh) {
this->age = rgh.age;
this->weight = rgh.weight;
this->name = (char*)malloc(12);
strcpy(this->name, rgh.name);
}
int getAge() {
return age;
}
int getWeight() {
return weight;
}
char* getName() {
return name;
}
};
int main() {
Student s;
Student s2 = s;
cout << s.getAge() << " " << s.getWeight() << endl;
cout << s2.getAge() << " " << s2.getWeight() << endl;
return 0;
}
防止使用拷贝构造
- 尽量使用引用
- 私有化拷贝构造函数
private:
student(const Student& rgh);
拷贝构造的参数可以传对象吗?
防止循环调用
继承
单继承
继承过来的成员,子类对象可以访问
#include<iostream>
using namespace std;
class People{//父类(基类)
private:
char name[12];
protected:
int money;
public:
int age;
int weight;
};
class Student: public People{//子类(派生类)
public:
int number;
int score;
void print(){
cout<<money<<weight<<endl;
}
};
int main(){
Student s;
s.age = 10;
return 0;
}
函数隐藏
- 如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名(只要函数名相同),那么就会隐藏从基类继承过来的成员。在派生类中使用该成员,实际上使用的时派生类新增的成员而不是从基类继承来的。
- 使用基类的成员函数
派生类.基类::print();
#include<iostream>
using namespace std;
class People{//父类(基类)
public :
int age;
int weigth;
void print(){
cout<<"People"<<endl;
}
};
class Student:public People{//子类(派生类)
public:
void print(){
cout<<"Student"<<endl;
}
};
int main(){
Student s;
s.print();
s.People::print();
return 0;
}
基类和派生类的构造析构顺序
#include<iostream>
using namespace std;
class People{
public:
People(){
cout<<"People"<<endl;
}
~People(){
cout<<"~People"<<endl;
}
};
class Student: public People{
public:
Student(){
cout<<"Student"<<endl;
}
~Student(){
cout<<"~Student"<<endl;
}
};
class CollegeStudent : public Student{//多重继承
public:
collegeStudent(){
cout<<"CollegeStudent"<<endl;
}
~collegeStudent(){
cout<<"~CollegeStudent"<<endl;
}
};
int main(){
CollegeStudent cs;
return 0
}
子类优先调用父类构造函数,然后调用子类的构造函数,然后调用子类的析构函数,最后调用父类的析构函数。
people,Student,~ Student,~ people
多继承
#include<iostream>
using namespace std;
class People{
protected:
int age;
public:
void dowork(){
cout<<"吃饭 睡觉 打豆豆"<<endl;
}
};
class Worker:public People{
public:
void dowork2(){
cout<<"板砖"<<endl;
}
};
class Farmer: public People{
public:
void doWork3(){
cout<<"种地"<<endl;
}
};
class MigrantWorker : public Worker,public Farmer{//多继承
};
int main(){
MigrantWorker mw;
//mw.dowork();
mw.doWork2();
mw.doWork3();
return 0;
}
- mw.doWork()???
- mw.age;???
虚继承
-
为什么存在
现象:加入我们有类A是父类,类B和类C继承了类A,而类D既继承类B又继承类C(这种菱形继承关系)。当我们实例化D的对象的时候,每个D的实例化对象中都有了两份完全相同的A的数据,因为保留多份数据成员的拷贝,不仅占用较多的存储空间,还增加了访问这些成员是的困难,容易出错,而实际上,我们并不需要有多份拷贝。
-
解决方案
#include<iostream>
using namespace std;
class People{
protected:
int age;
public:
void dowork(){
cout<<"吃饭 睡觉 打豆豆"<<endl;
}
};
class Worker:virtual public People{
public:
void dowork2(){
cout<<"板砖"<<endl;
}
};
class Farmer:virtual public People{
public:
void doWork3(){
cout<<"种地"<<endl;
}
};
class MigrantWorker :virtual public Worker,virtual public Farmer{//多继承
};
int main(){
MigrantWorker mw;
//mw.dowork();
mw.doWork2();
mw.doWork3();
return 0;
}
多态
new和malloc的区别
- new/delete是c++运算符那,需要编译器支持。malloc/free是库函数,需要头文件支持。
- 使用new操作符申请内存分配时无需指定内存的大小,编译器会根据类型信息自行计算。而malloc则需要显示地指出所需内存的尺寸。
- new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无需进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void*,需要通过强类型转换将void*指针转换成我们需要的类型。
- new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时会返回NULL。
- new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
#include<iostream>
using namespace std;
int main() {
int* p = (int*)malloc(sizeof(int));
p[0] = 100;
free(p);
int* n = new int;
*n = 200;
delete n;
int* a = new int[10];
a[8] = 10;
delete[] a;
return 0;
}
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
};
int main() {
People* p = (People*)malloc(sizeof(People));
free(p);
People* n = new People;
delete n;
return 0;
}
再谈函数隐藏
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
void play() {
cout << "吃饭 睡觉 打豆豆" << endl;
}
};
class Student :public People {
public:
void play() {
cout << "王者 吃鸡 英雄联盟" << endl;
}
};
int main() {
Student s;
s.play();
return 0;
}
函数重写/函数覆盖
- 父类定义虚函数
- 子类实现父类的虚函数
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
virtual void play() {
cout << "吃饭 睡觉 打豆豆" << endl;
}
};
class Student :public People {
public:
void play() {
cout << "王者 吃鸡 英雄联盟" << endl;
}
};
int main() {
Student s;
s.play();
return 0;
}
多态的实现
- 函数重写/函数覆盖
- 父类指针指向子类对象,并且调用子类的重写函数(运行的就是子类函数)
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
virtual void play() {
cout << "吃饭 睡觉 打豆豆" << endl;
}
};
class Student :public People {
public:
void play() {
cout << "王者 吃鸡 英雄联盟" << endl;
}
};
class Farmer :public People {
public:
void paly() {
cout << "玩地" << endl;
}
};
int main() {
Student s;
People* p = (People*)&s;
p->play();
//1.函数隐藏,调用的是哪个函数由指针变量类型决定
//2.函数重写,调用的是哪个函数由指针变量中存放的地址类型决定。
return 0;
}
多态的应用场景
- 存储
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
virtual void play() {
cout << "吃饭 睡觉 打豆豆" << endl;
}
};
class Student :public People {
public:
void play() {
cout << "王者 吃鸡 英雄联盟" << endl;
}
};
class Farmer :public People {
public:
void paly() {
cout << "玩地" << endl;
}
};
int main() {
Student s;
Student s2;
Student s3;
Farmer f1;
Farmer f2;
Farmer f3;
People p1;
People p2;
People p3;
People* vector[10] = {&s,&s2,&s3,&f1,&f2,&f3,&p1,&p2,&p3};
for (int i = 1; i < 10; i++) {
if (vector[i]) {
vector[i]->play();//不用判断
}
}
return 0;
}
- 参数
#include<iostream>
using namespace std;
class People {
public:
People() {
cout << "People" << endl;
}
~People() {
cout << "~People" << endl;
}
virtual void play() {
cout << "吃饭 睡觉 打豆豆" << endl;
}
};
class Student :public People {
public:
void play() {
cout << "王者 吃鸡 英雄联盟" << endl;
}
};
class Farmer :public People {
public:
void paly() {
cout << "玩地" << endl;
}
};
void printInfo(People* p) {
p->play();
}
int main() {
Student s;
Student s2;
Student s3;
Farmer f1;
Farmer f2;
Farmer f3;
People p1;
People p2;
People p3;
printInfo(&s2);
return 0;
}
静态成员
静态成员变量
#include<iostream>
using namespace std;
class People {
public:
int age;
static int water;//静态成员变量属于类而不属于对象
};
int People::water = 100;//类外初始化
int main() {
People p1;
People p2;
p1.water--;
People::water--;
cout << People::water << endl;
return 0;
}
静态成员函数
#include<iostream>
using namespace std;
class People {
private:
int age;
static int water;//静态成员变量属于类而不属于对象
public:
static void drink() {
water--;
}
static int getWater(){
return water;
}
};
int People::water = 100;//类外初始化
int main() {
People p1;
People p2;
People::drink();
cout << People::getWater()<< endl;
return 0;
}
缺省函数参数
#include<iostream>
using namespace std;
class Employee {
public:
Employee(int a, int b = 0, int c = 2) {
cout << "Employee" << endl;
}
};
int main() {
Employee(1);
return 0;
}
多态实例
//多态实例
#include<iostream>
#include<string>
using namespace std;
class Employee {
protected:
int m_id; //对象id
string m_name;
double m_salary;
static int id;//类id
public:
Employee() {
id++;
m_id = id;
m_name = "default name";
m_salary = 0.0;
}
virtual ~Employee() {
}
virtual double getPay() = 0;//纯虚函数,拥有纯虚函数的类叫做抽象类,抽象类不能被实例化。
virtual void show() {
cout << "姓名" << m_name << " ID:" << m_id << " 工资: " << getPay() << endl;
}
};
int Employee::id = 1000;
class Manager : virtual public Employee {
protected:
double m_base;
public:
Manager() {
}
Manager(string name) {
m_name = name;
m_base = 8000;
}
double getPay() {
m_salary = m_base;
return m_salary;
}
};
class Technician :public Employee {
protected:
int m_hour;
public:
Technician(string name, int hour = 0) {//缺省函数参数
m_name = name;
m_hour = hour;
}
double getPay() {
m_salary = m_hour * 100;
return m_salary;
}
};
class SalesMan :virtual public Employee {
protected:
double m_saleVolume;
static double totalSaleVolume;
public:
SalesMan() {
}
SalesMan(string name, double volume = 0.0) {
m_name = name;
m_saleVolume = volume;
totalSaleVolume += m_saleVolume;
}
double getPay() {
m_salary = m_saleVolume * 4 / 100;
return m_salary;
}
};
double SalesMan::totalSaleVolume = 0.0;
class SalesManager :public SalesMan, public Manager {
public:
SalesManager(string name){
m_base = 5000;
m_name = name;
}
double getPay() {
m_salary = m_base + totalSaleVolume * 5 / 100;
return m_salary;
}
};
int main(){
Manager m("hjm");
m.show();
Technician t1("gsp", 160);
t1.show();
Technician t2("shg", 180);
t2.show();
SalesMan s1("lmh", 100000);
s1.show();
SalesMan s2("lzy", 200000);
s2.show();
SalesMan s3("mcl", 250000);
s3.show();
SalesManager sm("mlh");
sm.show();
return 0;
}
纯虚函数
虚函数=0;
拥有纯虚函数的类成为抽象类,不能实例化
子类如果没有实例化父类的纯虚函数,那么子类也是抽象类
虚析构
virtual+析构函数
- 为什么要加虚析构
父类指针new子类对象,不会执行子类的析构函数,可能导致资源泄露。 - 为什么默认析构函数不是虚析构?
虚函数,会产生一个虚指针,浪费空间
虚指针
虚函数列表
内部类
#include<iostream>
using namespace std;
class People {
public:
class Baby {//在类内定义使用
public:
int age;
};
Baby b;
};
int main() {
People p;
p.b.age = 1;
People::Baby baby;//外部类名+作用域+内部类名
return 0;
}
内联函数
#include<iostream>
using namespace std;
class People {
int money;
public:
inline void print() {
//访问速度快(相当于是宏)1.短小 2.使用频率高
cout << money << endl;
}
};
int main() {
People p;
p.print();
return 0;
}
友元
友元函数
#include<iostream>
using namespace std;
class People {
private:
int age = 100;
public:
void printAge() {
cout << this->age << endl;
}
friend void printAge();//友元函数
friend int main(); //破坏了类的封装性
};
void printAge() {
People p;
cout << p.age << endl;
}
int main() {
People p;
cout << p.age << endl;
return 0;
}
友元类
#include<iostream>
using namespace std;
class People {
private:
int age = 100;
public:
void printAge() {
cout << this->age << endl;
}
friend class Animal;//友元类
};
class Animal {
private:
People p;
public:
void printPeopleAge() {
cout << p.age << endl;
}
};
int main() {
return 0;
}
常函数
#include<iostream>
using namespace std;
class People {
private:
int money;
public:
void print() const{
cout << money << endl;
//money = 10;//不可以修改类属性
}
};
int main() {
People p;
p.print();
return 0;
}
重载运算符
c++允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。重载的运算符是带有特殊名称的函数,函数名是由关键字operator和其后要重载的运算符符号构成的,与其他函数一样,重载运算符有一个返回类型和一个参数列表。
//小任务
//Box.cpp
#include"box.h"
void Box::setBreadth(double bre)
{
breadth = bre;
}
void Box::setHeight(double hei)
{
height = hei;
}
//重载 + 运算符, 用于把两个Box对象相加
Box::Box() = default;
Box::Box(const Box& box)
{
this->height = box.height;
this->breadth = box.breadth;
this->length = box.length;
}
Box::Box(const Box& box)
{
this->height = box.height;
this->breadth = box.breadth;
this->length = box.length;
}
Box Box::operator=(const Box& b) {
height = b.height;
breadth = b.breadth;
length = b.length;
}
Box Box::operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
Box Box::operator++() {
this->length += 1;
this->breadth += 1;
this->height += 1;
return *this;
}
Box Box::operator++(int)
{
Box tmp = *this;
this->length += 1;
this->breadth += 1;
this->height += 1;
return tmp;
}
//Box.h
#pragma once
class Box
{
public:
double getVolume(void);//球体积
void setLength(double len);//设置长
void setBreadth(double bre);//设置宽
void setHeight(double hei);//设置高度
//重载 + 运算符,用于把两个box对象相加;
Box();
Box(const Box& box);
Box operator=(const Box& b);
Box operator+(const Box& b);
Box operator++();//重载 前++
Box operator++(int);//重载 后++
private:
double length; //长度
double breadth;//宽度
double height; //高度
};
//main.cpp
#include<iostream>
#include "Box.h"
using namespace std;
//程序的主函数
int main() {
Box box1;
box1.setBreadth(6.0);
box1.setHeight(6.0);
box1.setLength(9.0);
Box box2(box1);
return 0;
}