cin>>变量
cout<<输出项<- endl相当于
- 输出项可以是字符串,也可以是变量
三.内存分区模型- 意义
- 对不同区域存放的数据赋予不同的生命周期
- 分区
代码区:存放函数体的二进制代码,由操作系统进行管理
- 程序执行前出现
- 存放CPU执行的机器指令
- 代码区数据共享(不用反复生成)
- 代码区数据只读(不可修改)
全局区:存放全局变量和静态变量以及常量(const修饰的全局常量和字符串常量)
- 程序执行前出现
- 存储全局变量和静态变量和常量
- 程序执行 完后由操作系统释放
栈区:由编译器自动分配释放,存放函数的参数值,局部变量,局部常量,形参数据等
- 注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
如:
#includeusing namespace std;
int* func()
{int a = 10;
return &a;//返回局部变量的地址
}
int main()
{int* p = func();
cout<< *p<< endl;//#10 第一次打印正确数字因为编译器替你保留了一次
cout<< *p<< endl;//#???第二次这个数据就不保留了(visual studio2022编译器会一直保留)
system("pause");
return 0;
}
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
- 在c++中主要利用new在堆区开辟内存
- 语法:
int *p=new int(10)
int *arr=new int[10]
new int(10)
返回的是开辟的内存的首地址,所以用指针去接收- (10)表示初始值为10
- [10]表示开辟10个元素
- 在c++中主要利用delete在堆区释放内存
- 语法:
delete p
delete[] arr
- p是之前开辟的内存地址,直接delete内存地址即可释放
- 释放数组空间需要加[]
四.引用- 作用:给变量取别名,共用同一个内存空间
- 语法:
数据类型 &别名=原名
- 注意事项
- 引用必须初始化
- 错误:
int &b;
- 引用在初始化后不可以改成别的别名
- 错误:
int &b=a;
int &b=c;//更改引用成别的变量的别名会报错
- 引用形参
- 作用:用形参修饰实参
- 有点:比指针方便
- 函数参数传递对比
值传递(形参不修饰实参)
//1.值传递
void val_swap(int a, int b)
{int temp = a;
a = b;
b = temp;
}
int main()
{int a = 10;
int b = 20;
val_swap(a, b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}

地址传递(形参修饰实参)
//2.地址传递
void address_swap(int *a, int *b)
{int temp = *a;
*a = *b;
*b = temp;
}
int main()
{int a = 10;
int b = 20;
val_swap(&a, &b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}

引用传递(形参修饰实参)
//3.引用传递
void quote_swap(int &a, int &b)
{int temp = a;
a = b;
b = temp;
}
int main()
{int a = 10;
int b = 20;
quote_swap(a, b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}

- 引用做函数返回值
作用:作为函数返回值
注意:不要返回局部变量的引用
代码:
int& test1()
{int a = 10;
return a;
}
int main()
{int &ref = test1();
cout<< ref<< endl;//10
cout<< ref<< endl;//???(但是visual studio 2022编译器永久保留了内存,所以也是10)
system("pause");
return 0;
}
int& test2()
{static int a = 10;//堆区的静态变量
return a;
}
int main()
{int &ref1 = test2();
cout<< ref1<< endl;//10
cout<< ref1<< endl;//10
test2() = 1000;//左值(作为等号左边)
cout<< test2()<< endl;//1000 a的别名是test2()
cout<< ref1<< endl;//1000 a的别名是ref1
system("pause");
return 0;
}
- 引用的本质
本质:指针常量(指针的指向不可以修改,指针指向的值是可以改动的)(引用相当于加了一个限制(不可以指向别的地方)的指针)(转换出来的const修饰的是变量名,即地址,所以指向不可以修改)
代码:
//引用的本质(编译器自动将引用转化成指针常量形式)
void func(int "e)//->void func(int *const quote)
{quote = 30;//->*quote=30
}
int main()
{int a = 10;
int "e = a;//->int *const quote=&a
quote = 20;//->*quote=20
cout<< a<< endl;
cout<< quote<< endl;//->cout<<*quote<func(&a)
cout<< a<< endl;
cout<< quote<< endl;//->cout<<*quote<
常量引用本质:(指针的指向不可以修改,指针指向的值是也不可以修改)
作用:常量引用主要用来修饰形参,防止形参改变实参
//常量引用
void func(const int& ref)
{//无法通过修改ref的值去改变main中的值,防止误操作
//ref = 1000;
cout<< ref<< endl;
}
int main()
{//引用本身需要一个合法的内存空间,所以下面注释掉的这行是错误的,得用下下行
//int& ref = 10;
const int &ref = 10;//->const int temp=10;const int &ref=temp;
int a = 10;
func(a);
system("pause");
return 0;
}
五.函数(区别于C语言)- 函数默认参数
语法:返回值类型 函数名(参数1,参数2=默认值,参数3=默认值,···){}
注意:
- 如果形参列表中某个位置有了默认值,那么这个位置之后所有位置都要先设置默认值
- 如果函数声明有默认参数,函数实现中就不能写默认参数,否则会出现二义性
代码:
//函数默认参数
int func(int a, int b = 10, int c = 20)
{return a + b + c;
}
int main()
{cout<< func(10,30)<< endl;
system("pause");
return 0;
}
- 函数占位参数(占位参数也可以有默认参数)
- 语法:
返回值类型 函数名(数据类型){}
返回值类型 函数名(数据类型 = 值){}
- 注意:调用带占位参数的函数需要填补占位参数
- 代码:
//函数占位参数
void func(int a, int)
{cout<< "不知道有啥用"<< endl;
}
int main()
{func(10, 20);
system("pause");
return 0;
}
- 函数重载
- 作用:函数名可以相同,提高复用性
- 函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者参数个数不同或者参数顺序不同
- 注意:
- 函数的返回值不可以进行函数重载
- 形参名字不同不可以进行函数重载
- 代码:
void func()
{cout<< "func()的调用"<< endl;
}
//参数类型不同
void func(int a)
{cout<< "func(int a)的调用"<< endl;
}
void func(double a)
{cout<< "func(double a)的调用"<cout<< "func(int a, double b)的调用"<< endl;
}
//参数顺序不同
void func(double a, int b)
{cout<< "func(double a, int b)的调用"<< endl;
}
int main()
{func();//第一个函数的调用
func(10);//第二个函数的调用
func(10.0);//第三个函数的调用
func(10, 10.0);//第四个函数的调用
func(10.0, 10);//第五个函数的调用
}
- 引用作为重载条件
代码:
//1.引用作为重载的条件
void func(int &a)
{cout<< "func(int &a)调用"<< endl;
}
void func(const int &a)//引用常量
{cout<< "func(const int &a)调用"<< endl;
}
int main()
{int a = 0;
func(a);//第一个函数被调用
func(0);//第二个函数被调用
system("pause");
return 0;
}
- 函数重载碰到函数默认参数(写函数重载时尽量不要有默认参数,否则容易出现如下的二义性)
代码:
//2.函数重载碰到默认参数
void func(int a,int b=10)
{cout<< "func(int a,int b=10)调用"<< endl;
}
void func(int a)//引用常量
{cout<< "func(int a)调用"<< endl;
}
int main()
{//func(10);//这样是调用不了的
func(10, 20);//这样才能调用
system("pause");
return 0;
}
六.类和对象C++面向对象特性:封装、继承、多态
类和结构体的唯一区别
- struct的默认权限为公共,class默认权限为私有
封装
- 封装的意义
- 将属性和行为作为一个整体,表现生活中的事物
- 语法:
class 类名
{访问权限
属性
行为
};
类名 变量名;
- 将属性和行为加以权限控制
访问权限
权限 语法 特点 继承方面特点 公共权限 public 类内可以访问,类外可以访问 保护权限 protected 类内可以访问,类外不可以访问 子类继承父类后可以访问 私有权限 private 类内可以访问,类外不可以访问 子类继承父类后还是不可以访问
- 一般通过访问公共成员函数去对私有成员属性进行读写操作
- 优点
- 自己控制读写权限
- 检测用户输入数据是否有效
- 代码:
class Person
{public:
//可读可写
void setName(string name)
{m_Name = name;
}
string getName()
{return m_Name;
}
//只读
int getAge()
{m_Age = 0;
return m_Age;
}
//只写
void setFriend(string Friend)
{m_friend = Friend;
}
private:
string m_Name;
int m_Age;
string m_friend;
};
int main()
{Person p;
p.setName("张三");
cout<< p.getName()<< endl;
cout<< p.getAge()<< endl;
p.setFriend("friend");
system("pause");
return 0;
}
对象特性
对象的初始化和清理
- 构造函数(自动调用)
- 作用:创建对象时为对象的成员属性赋值
- 语法:
类名(){};
- 特点:
- 无返回值,也不写void
- 构造函数的函数名就是该类的类名
- 构造函数可以有形参,可发生重载
- 在调用对象时系统自动调用且只调用一次
- 需要注意构造函数也有访问权限,如果不声明公共权限,类外创建对象会无法自动调用构造函数,会报错
- 分类:
- 按参数分类:
- 有参构造
- 语法:
类名(数据类型 变量名){};
- 无参构造(默认构造)
- 语法:
类名(){};
- 按类型分类:
- 普通构造
- 拷贝构造
- 调用时机(黑马P108,没听懂,太难了)
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
- 返回的是一个副本对象,与原本对象不在同一个内存空间
- 深拷贝与浅拷贝(如果成员属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题)
浅拷贝:简单的赋值拷贝操作(使用指针时先拷贝会指向同一片内存空间,前后两个指针指向同一块内存空间)
深拷贝:在堆区重新申请空间,进行拷贝操作(在自己写的拷贝构造函数中重新申请空间)(使用指针时深拷贝会指向别的地方的内存空间,前后两个指针之间没有交集)
代码:
#includeusing namespace std;
class Person
{public:
Person()
{cout<< "默认构造"<< endl;
}
Person(int age,int height)
{m_Age = age;
m_Height = new int(height);//括号内放的是元素
cout<< "有参构造"<< endl;
}
Person(const Person& p)
{cout<< "深拷贝构造"<< endl;
m_Age = p.m_Age;
//m_Height = p.m_Height;//这是编译器默认实现的代码,是浅拷贝
m_Height = new int(*p.m_Height);//深拷贝
}
~Person()
{if (m_Height != NULL)
{ delete m_Height;
m_Height = NULL;
}
}
int m_Age;
int *m_Height;
};
void test1()
{Person p1(10,160);
cout<< p1.m_Age<<*p1.m_Height<< endl;
Person p2(p1);
cout<< p2.m_Age<< *p2.m_Height<test1();
system("pause");
return 0;
}
- 调用方式
- 括号法
注意:调用默认构造函数时不要加(),即不要类名 变量名();
,因为编译器会认为i这是函数的声明;
代码:
//1.括号法
Person p1(10);//使用有参构造
Person p2(p1);//使用拷贝构造
cout<< p1.age<< p2.age<
显式法注意:
类名(实参);
是匿名对象,当前行执行结束后,系统会立即回收掉匿名对象
不要利用拷贝构造函数初始化匿名对象,编译器会自动去掉括号认为在定义,就会出现重定义报错
代码:
Person p1 = Person(10);//使用有参构造
Person p2 = Person(p1);//使用拷贝构造
Person(10);//匿名对象 对
Person(p1);//错
Person(p2);//错
代码:
//2.显示法
Person p1 = Person(10);//使用有参构造
Person p2 = Person(p1);//使用拷贝构造
隐式转换法代码:
//3.隐式转换法
Person p4 = 10;//->Person p4=Person(10)//使用有参构造
Person p5 = p4;//->Person p5=Person(p4)//使用拷贝构造
析构函数(自动调用)- 作用:在对象销毁前系统自动调用执行请理工作(将堆区开辟数据做释放)
- 语法:
~类名(){}
- 特点:
- 无返回值,也不写void
- 析构函数的函数名就是~+该类的类名
- 析构函数不可以有形参,所以不可以发生重载
- 在销毁对象前系统自动调用且只调用一次
代码:
#includeusing namespace std;
class Person
{public:
//1.构造函数
Person()
{cout<<"Person构造函数调用"<< endl;
}
//2.析构函数
~Person()
{cout<< "Person析构函数调用"<< endl;
}
};
int main()
{Person person;//创建对象后就出现构造调用
system("pause");//按任意键后出现析构调用,因为main函数执行完后销毁了对象
return 0;
}
调用规则:
首先默认情况下编译器至少给一个类添加3个函数:- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝(参数为:
const 类名 &变量名
)
如果用户定义有参构造函数,c++不再提供默认的无参构造,但是会提供默认拷贝(即用户只提供有参,编译器不会提供无参,但提供拷贝)- 因此如果你只写有参构造,但不写默认构造,然后去调用默认构造编译器会报错
如果用户定义拷贝构造函数,c++不会再提供其他构造函数(即用户只提供拷贝,编译器不会提供无参,也不会提供有参)- 因此如果你只写拷贝构造,但不写默认构造和有参构造,然后去调用默认构造或有参构造编译器会报错
初始化列表
语法:构造函数类名():属性1(值1或变量1),属性2(值2或变量2){}
代码:
#includeusing namespace std;
class Person
{public:
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{;
}
int m_A;
int m_B;
int m_C;
};
int main()
{Person p(10,20,30);
cout<< p.m_A<< p.m_B<< p.m_C<< endl;
system("pause");
return 0;
}
类对象作为类成员
注意:
构造顺序:当其他类对象作为本类成员,构造时先构造类对象,再构造自身(先里再外)
析构顺序:当其他类对象作为本类成员,析构时先析构自身,再析构类对象(先外再里)
代码
#includeusing namespace std;
//类对象作为类成员
class Phone
{public:
Phone()
{m_PhoneNum = 12345678901;
}
long long int m_PhoneNum;
};
class Person
{public:
Phone m_Phone;
};
int main()
{Person p;
cout<< p.m_Phone.m_PhoneNum<< endl;//12345678901
system("pause");
return 0;
}
静态成员(静态可以理解为共用)
定义:在成员变量和成员函数前加上关键字static
语法:static a;
或
分类:- 静态成员变量(全局区)
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化(类外定义)
- 类内:
static 变量类型 变量名;
- 类外:
变量类型 类名::变量名;
- 表示定义类名作用域下变量名这个静态成员
- 访问方式:
- 通过对象进行访问
- 语法:
类名 变量名;变量名.静态成员变量;
- 通过类名进行访问(类名作用域)
- 语法:
类名::静态成员变量;
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量,不可以访问非静态成员变量
- 因为当使用访问方式2去访问时,不知道改变的非静态成员变量是属于哪个对象的
- 访问方式:
- 通过对象进行访问
- 语法:
类名 变量名;变量名.静态成员函数;
- 通过类名进行访问(类名作用域)
- 语法:
类名::静态成员函数;
区别:- 静态成员函数不需要初始化(定义),和静态成员变量不同
C++对象模型和this指针
成员变量和成员函数分开存储
空对象占用内存空间为1
C++编译器会给每个空对象分配一个字节空间,是为了区分各个空对象占内存的位置,将它们分隔开(每一个空对象都应该有一个独一无二的空间)
除了非静态成员变量属于类的对象,占用正常变量类型的字节,其余(静态成员变量,非静态成员函数,静态成员函数)都不属于类的对象,不占用字节
代码
class Person
{public:
int m_A;//非静态成员变量,属于类的对象上//即属于p//占4字节
static int m_B;//静态成员变量,不属于类的对象上//即不属于p//所以占用字节为0
void func1() {};//非静态成员函数,也是不属于类的对象上//即不属于p//所以占用字节为0//比较特殊
static void func2(){}//静态成员半数,不属于类的对象上//即不属于p//所以占用字节为0
};
this指针
本质:指针常量(this指针指向不可以修改,this指针指向的值是可以修改的)
概念:this指针指向被调用的成员函数所属的对象(哪个对象调用了成员函数(得先调用成员函数,才能让this指针指向),this指针就指向谁)
用途
当形参和成员变量同名时,可以用this指针区分
在类的非静态成员函数中返回对象本身,可以用return *this- 即this指针指向对象,解引用this即可得到对象
代码:
#includeusing namespace std;
class Person
{public:
Person(int m_Age)
{this->m_Age=m_Age;//this 指向调用了该成员函数的对象p,所以使用p->age去接收形参m_Age
}
//返回值用引用返回的就是对象本体,指向本身内存,如果不用引用返回的是对象副本,与对象没有关系,后续的操作就改变不了对象
Person &PersonAdd(Person& p)//不懂这里的返回值为什么是Person &,不能是Person或Person *
{this->m_Age += p.m_Age;
//this是指向调用了这个函数的对象,在这里是p3
return *this;
}
int m_Age;
};
//1.解决名称冲突
void test1()
{Person p1(10);
cout<< p1.m_Age<< endl;//10
}
//2.返回对象本身用*this
void test2()
{Person p2(1);
Person p3(2);
//链式编程思想//cout<<<<也是链式编程思想
p3.PersonAdd(p2).PersonAdd(p2);//2+1+1//如果使用Person PersonAdd(p2)则这个地方会调用p3的默认拷贝构造函数,返回的是一个新副本,与p3不在同一个内存空间
cout<< p3.m_Age<< endl;//4
}
int main()
{test1();
test2();
system("pause");
return 0;
}
空指针访问成员函数
注意:有没有用到this指针,如果用来this指针就要加判断保证代码的健壮性
代码:
#includeusing namespace std;
//空指针调用成员函数
class Person
{public:
void showName()
{cout<< "Name"<< endl;
}
void showAge()
{if(this==NULL)//不懂这里为什么不是*this==NULL
{ return;
}
cout<< m_Age<< endl;//这个报错原因是因为默认将m_Age变成this->m_Age,但此时this指向是NULL,所以报错
}
int m_Age = 10;
};
void test1()
{Person *p=NULL;//空指针
p->showName();
p->showAge();
}
int main()
{test1();
system("pause");
return 0;
}
const修饰成员函数
常函数:
成员函数后加const为常函数
语法:函数返回类型 函数名() const{}
常函数内不可以修改成员属性- 因为this指针(类名 *const this)(指针常量)变成了(const 类名 *const this)(常指针常量)(此时指针指向的值也不可以修改了)
成员属性(成员变量)声明时加关键字mutable后,在常函数中依然可以修改
常对象(不能通过对象.成员变量
的方式修改成员变量值,除非成员变量声明时加关键字mutable):
声明对象前加const称该对象为常对象
常对象只能调用常函数
代码:
#includeusing namespace std;
//常函数
class Person
{public:
void showPerson() const
{//this->m_A = 100;//让指针指向的值也不可以改变
this->m_B = 100;//成员变量加mutable关键字后可以修改
}
void func()
{}
int m_A;
mutable int m_B;//特殊变量,加上关键字mutable后,即使在常函数中,也可以修改这个值
};
int main()
{const Person p2;//常对象
//p2.m_A=10;//报错//常对象不能修改成员属性值,除非成员变量声明时前面加mutable
p2.m_B = 10;
//常对象只能调用常函数
p2.showPerson();
//p2.func();//报错//常对象不可以调用普通成员函数,因为普通成员函数可以修改成员属性值,而常对象定义就是不能修改成员属性值
system("pause");
return 0;
}
友元
关键字:friend
目的:让类外特殊的一些函数或者类访问改类中的私有成员
友元的三种实现:- 全局函数做友元
语法:在类中写friend 函数声明
即可在类外使用该函数对类中的私有属性进行访问
代码:
#include#includeusing namespace std;
class Building
{//friend 加上这一句函数声明即可在类外使用该函数去访问私有属性
friend void goodGay(Building &building);
public:
Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
//全局函数
void goodGay(Building &building)
{cout<< building.m_SittingRoom<< endl;
cout<< building.m_BedRoom<< endl;
}
void test1()
{Building b;
goodGay(b);
}
int main()
{test1();
system("pause");
return 0;
}
- 类做友元
语法:在类1中写friend 类2声明
即可使用类2中的所有成员函数去访问类1的私有属性
代码:
#include#includeusing namespace std;
//类做友元
class Building;//类声明
class GoodGay
{public:
GoodGay();//先在类内声明
void visit();//先在类内声明
Building *b;
};
class Building
{friend class GoodGay;//友元+类声明后可以使用该类去访问给出友元的类的私有属性
public:
Building();//先在类内声明
string m_SittingRoom;
private:
string m_BedRoom;
};
//再在类外写成员函数,需要声明在该类域下
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
cout<< b->m_BedRoom<< endl;//使用友元访问私有属性
}
//再在类外写成员函数,需要声明在该类域下
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
};
void test1()
{GoodGay g;
g.visit();
}
int main()
{test1();
system("pause");
return 0;
}
- 成员函数做友元
语法:在类1中写friend 成员函数返回类型 类2名字::成员函数名();
即可使用类2中的该成员函数去访问类1的私有属性
代码:
#include#includeusing namespace std;
class Building;
class GoodGay
{public:
GoodGay();
void visit();//让visit函数可以访问Building中私有成员
Building *b;
};
class Building
{friend void GoodGay::visit();//GoodGay类下的visit函数作为Building类的友元可以访问Building类的私有属性
public:
Building();
string m_SittingRoom;
private:
string m_BedRoom;
};
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
cout<< b->m_BedRoom<< endl;
}
void test()
{GoodGay g;
g.visit();
}
int main()
{test();
system("pause");
return 0;
}
类外写成员函数
代码:
class Building;
class GoodGay
{public:
GoodGay();//先在类内声明
void visit();//先在类内声明
Building *b;
};
class Building
{public:
Building();//先在类内声明
string m_SittingRoom;
private:
string m_BedRoom;
};
//再在类外写成员函数,需要声明在该类域下
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
}
//再在类外写成员函数,需要声明在该类域下
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
};
运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
注意:- 编译器会自动简化运算符
- 运算符重载也可以发生函数重载
- 对于内置的数据类型的表达式的运算符是不可能改变的,比如(1+1=2,float,int等数据类型),自定义的数据类型才可以改变
- 不要滥用运算符重载
常用:成员函数和全局函数进行运算符重载
分类:- 加号运算符重载
关键:operator<<
作用:实现两个自定义数据类型相加的运算
代码:
#includeusing namespace std;
//加号运算符重载
//1.成员函数重载+号
class Person1
{public:
Person1()
{m_A = 10;
m_B = 20;
}
Person1 operator+(Person1& p)
{Person1 temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
int m_A;
int m_B;
};
void test1()
{Person1 p1;
Person1 p2;
Person1 p3 = p1+p2;//被编译器简化了,原本应该写成Person1 p3 = p1.operator+(p2);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//20 40
}
//2.全局函数重载+号
class Person2
{public:
Person2()
{m_A = 10;
m_B = 20;
}
int m_A;
int m_B;
};
Person2 operator+(Person2 &p1, Person2 &p2)
{Person2 temp;
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
void test2()
{Person2 p1;
Person2 p2;
Person2 p3 = p1 + p2;//被编译器简化了,原本应该写成Person2 p3 = operator+(p1,p2);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//20 40
}
//3.全局函数使用函数重载+号
class Person3
{public:
Person3()
{m_A = 10;
m_B = 20;
}
int m_A;
int m_B;
};
Person3 operator+(Person3& p1, int num)
{Person3 temp;
temp.m_A = p1.m_A + num;
temp.m_B = p1.m_B + num;
return temp;
}
void test3()
{Person3 p1;
Person3 p3 = p1 + 100;//被编译器简化了,原本应该写成Person3 p3 = operator+(p1,100);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//110 120
}
int main()
{test1();
test2();
test3();
system("pause");
return 0;
}
- 左移运算符重载
关键:operator<<
作用:自定义<<
注意:
- 一般不用成员函数进行左移运算符重载,而是使用全局函数
- 重载左移运算符配合友元可以实现输出自定义数据类型
代码:
#includeusing namespace std;
1.成员函数重载左移运算符
//class Person1
//{//public:
// Person1()
// {// m_A = 10;
// m_B = 20;
// }
// //通常不会利用成员函数重载<<运算符,因为无法实现cout在左侧
// //p.operator<//
// //}
// int m_A;
// int m_B;
//};
//
//void test1()
//{// Person1 p1;
// cout<< p1<< endl;
//}
//2.成员函数重载左移运算符
class Person2
{friend ostream& operator<<(ostream& cout, Person2& p2);//简化为 cout<m_A = 10;
m_B = 20;
}
private:
int m_A;
int m_B;
};
ostream &operator<<(ostream &cout, Person2 &p2)//简化为 cout<
cout<< "m_A="<< p2.m_A<< "m_B="<< p2.m_B ;
return cout;
}
void test2()
{Person2 p2;
cout<< p2<<"hi"<< endl;//可是这时用了endl后时传参给p2吗,好奇怪//因为这里发生了函数重载,endl或者"hi"的类型和Person2不同,所以不会调用自定义左移运算符,而是用系统自带的
}
int main()
{//test1();
test2();
system("pause");
return 0;
}
- 递增运算符重载
作用:通过重载递增运算符,实现自己的整型数据
注意:
- 前置递增需要返回引用
- 后置递增不能返回引用(因为是局部对象,函数执行完后会被释放掉),要返回值
代码:
#includeusing namespace std;
//重载递增运算符
//自定义整形
class MyInteger
{friend ostream &operator<<(ostream& cout, MyInteger myint);
public:
MyInteger()
{m_Num = 0;
}
//重载前置++运算符//不需要传参
MyInteger &operator++()//返回类型得用引用,不用引用的话只是副本//返回引用是为了一直对一个数据进行递增操作
{this->m_Num++;//先自身做加加运算
return *this;//再对自身做一个返回
}
//重载后置++运算符
MyInteger operator++(int)//int(也只能用int)代表占位参数,可以用于区分前置递增运算符和后置递增运算符//不能返回引用,因为函数执行完后temp会被释放掉,需要一个副本
{//先 记录此时的结果
MyInteger temp = *this;//temp是局部对象,不能返回引用,因为函数执行完后temp会被释放掉
//后 让自身的值++
this->m_Num++;
//最后将之前记录的结果返回
return temp;
}
private:
int m_Num;
};
//重载<<运算符
ostream &operator<<(ostream& cout, MyInteger myint)
{cout<< myint.m_Num;
return cout;
}
void test1()
{MyInteger myint;
cout<< ++myint<< endl;
}
void test2()
{MyInteger myint;
cout<< (myint++)++<< endl;
cout<< myint<< endl;
}
int main()
{//test1();
test2();
system("pause");
return 0;
}
- 赋值运算符号重载
- c++编译器至少给一个类加4个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
- 赋值运算符operator=,对属性进行值拷贝
- 注意:
- 如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
分享标题:C++知识点的回顾(持续更新)-创新互联
分享URL:http://hzjierui.cn/article/gshej.html
售后响应及时
7×24小时客服热线
数据备份
更安全、更高效、更稳定
价格公道精准
项目经理精准报价不弄虚作假
合作无风险
重合同讲信誉,无效全额退款