C++ 学习笔记(五)类的知识小结一(重载,友元函数,静态成员,new)
---恢复内容开始---
学习C++类知识点还是挺多的,每个知识点学习的时候都觉得这个知识点咋那么多东西,其实真学完了再回头看好像也就那么点。这次用程序写一个黑猫揍白猫的故事总结一下这段时间学习的零碎知识点。包括以下几点:
1.重载:函数重载 、运算符重载
2.友元函数
3.静态成员变量
4.new / delete 关键字和 malloc / free函数的区别
程序将实现一个Cat类,定义一只黑猫一只白猫。用户喂食黑猫为黑猫增加武力值,之后用户给白猫喂食,为白猫增加生命值,两只猫都喂食完后黑猫就揍白猫一次。等到白猫生命值为0时或者食物喂完了程序结束(原谅我想不到更好的、又简单、又能符合想记录的知识点需求 的故事,只能无厘头的让白猫一直挨揍了)。。。
Cat类的定义:Cat.h
1 #pragma once 2 #include <iostream> 3 #include <string> 4 5 #define CAT_ATTRIBUTE 1 6 7 #define FORCE_MAX 100 8 #define HP_MAX 100 9 10 #define CAT_MALE 1+CAT_ATTRIBUTE 11 #define CAT_FEMALE 2+CAT_ATTRIBUTE 12 13 using namespace std; 14 15 class Cat 16 { 17 /*公有成员:此类的对象可以直接使用*/ 18 public: 19 static int food; //静态成员变量 20 21 Cat(string name ,int sex = CAT_MALE); //构造函数,创建一个对象时自动调用 22 Cat(string name ,int sex , unsigned int force_value = 20); //函数的重载 23 ~Cat(); //析构函数,没有返回值没有传参,delete对象时自动调用 24 25 int add_hp(int add_value); //普通成员函数 26 void report_state(); //普通成员函数 27 int get_hp(); 28 int eat_food(int value); 29 friend unsigned int add_force(Cat *cat,int add_value); //友元函数(全局函数可访问类的私有成员) 30 31 32 int operator-(Cat *cat); //- 运算符重载 33 int operator--(); //前置-- 运算符重载 34 int operator--(int); //后置-- 运算符重载(使用占位参数说明是后置运算符重载) 35 36 37 /*私有成员:只能通过本类的公有函数和友元函数进行读写*/ 38 private: 39 string name; 40 int sex; //性别 41 int HP; //生命值 42 unsigned int force_value; //武力值 43 44 };
Cat类的实现:Cat.cpp
1 #include "cat.h" 2 3 int Cat::food = 100; //初始化静态变量 4 Cat::Cat(string name ,int sex) //构造函数,创建一个对象时自动调用 5 { 6 /*设置初始值*/ 7 this->name = name; 8 this->sex = sex; 9 this->HP = 100; 10 this->force_value = 20; 11 /*打印状态*/ 12 cout<<" creat a new cat !! "<<endl; 13 this->report_state(); 14 } 15 16 Cat::Cat(string name ,int sex , unsigned int force_value ) //构造函数,创建一个对象时自动调用 17 { 18 /*设置初始值*/ 19 this->name = name; 20 21 this->sex = sex; 22 this->HP = 100; 23 this->force_value = force_value; 24 /*打印状态*/ 25 cout<<" creat a new cat !! "<<endl; 26 this->report_state(); 27 28 } 29 30 Cat::~Cat()//析构函数,没有返回值没有传参,delete对象时自动调用 31 { 32 cout<<"cat "<<this->name<<" was dead"<<endl; 33 } 34 35 36 void Cat::report_state() 37 { 38 cout<< " ---------I am "<<this->name<<"----------" <<endl; 39 cout<< "my hp :"<<this->HP<<endl; 40 cout<< "my force value:"<<this->force_value<<endl; 41 cout<<"-------------------------------------"<<endl; 42 } 43 44 int Cat::add_hp(int add_value) 45 { 46 this->HP += add_value; 47 return this->HP; 48 } 49 50 int Cat::operator-(Cat *cat)//- 运算符重载 51 { 52 cat->HP -= this->force_value; 53 if(cat->HP < 0) 54 cat->HP = 0; 55 cout<<this->name<<" hit - > "<<cat->name<<endl; 56 return cat->HP; 57 } 58 59 int Cat::operator--()//前置-- 运算符重载 60 { 61 if(this->HP > 0 ) 62 this->HP -=1; 63 return this->HP; 64 } 65 66 int Cat::operator--(int)//后置-- 运算符重载(使用占位参数说明是后置运算符重载) 67 { 68 int temp = this->HP; 69 if(this->HP > 0 ) 70 this->HP -=1; 71 72 return temp; 73 } 74 75 int Cat::get_hp() 76 { 77 return this->HP; 78 } 79 80 81 int Cat::eat_food(int value)//将减少静态成员变量food的值 82 { 83 food -= value; 84 if(Cat::food<0){ 85 cout<<"food is used up !!"<<endl; 86 Cat::food = 0; 87 } 88 return Cat::food; 89 } 90 91 92 /*友元函数 可以通过传入对象 操作其私有属性*/ 93 unsigned int add_force(Cat *cat,int add_value) 94 { 95 cat->force_value += add_value; 96 if(cat->force_value > FORCE_MAX) 97 cat->force_value = FORCE_MAX; 98 return cat->force_value; 99 }
main函数:main.cpp
1 #include <iostream> 2 #include <string> 3 #include "cat.h" 4 5 using namespace std; 6 int main(int argc, char **argv) 7 { 8 int add_value = 0; 9 Cat black("black",CAT_MALE,10); //黑猫出生(调用构造函数) 10 Cat* white; 11 white = new Cat("white"); //白猫出生( 函数重载;new将分配堆中的内存,使用完毕需要delete) 12 13 black--; //黑猫作死,扣一点血(后置--运算符重载) 14 cout<<"black cat's HP :"<<black.get_hp()<<endl; 15 16 --*white; //白猫学黑猫作死,扣一点血(前置--运算符重载) 17 cout<<"white cat's HP:"<<white->get_hp()<<endl; 18 19 /*如果黑猫白猫都还活着并且还有食物程序继续运行*/ 20 while(black.get_hp() >0 && white->get_hp()>0 &&Cat::food ) 21 { 22 cout<<"How much food do you want to feed for black cat "<<endl; 23 cin>>add_value; 24 black.eat_food(add_value); 25 cout<<"black's force :"<<add_force(&black,add_value)<<"\n"<<endl; //调用友元函数添加黑猫武力值 26 27 cout<<"How much food do you want to feed for white cat "<<endl; 28 cin>>add_value; 29 white->eat_food(add_value); //将减少静态成员food的值,这个food是整个Cat类共享的 30 cout<<"white's hp :"<<white->add_hp(add_value)<<"\n"<<endl; 31 32 black-white; //‘-’运算符重载的使用 33 cout<<"white cat's HP"<<white->get_hp()<<endl; 34 cout<<"food still have "<<Cat::food<<endl; 35 } 36 37 white->report_state(); 38 black.report_state(); 39 delete white; //使用new分配的内存需要释放 40 system("pause"); 41 return 0; 42 }
运行结果:
知识点总结:
1.函数重载 、参数默认值
本次例程中实现了两个Cat构造函数,传入参数不同
a.定义
Cat(string name ,int sex = CAT_MALE); //构造函数,创建一个对象时自动调用
Cat(string name ,int sex , unsigned int force_value = 20); //函数的重载
函数重载的判断标准是传参:传参的个数,传参的类型。
返回值不能作为函数重载的标准,即传参一样返回值类型不同的是会被认为函数重定义的。
b.使用
在main函数9行,定义black 的时候传入了三个参数很明显是调用了
Cat(string name ,int sex , unsigned int force_value = 20);
在new一个white的时候只传入了一个参数,其实调用了
Cat(string name ,int sex = CAT_MALE);
在Cat.h文件中我们可以看到sex = CAT_MALE;当没有传参的时候便使用这个默认参数。
而从黑猫的创建中因为传入force_value = 10,所以默认的20失效。
2.运算符重载
本例程重载了-、后置--、前置-- 三个运算符。运算符重载其实也是实现函数,只是函数名比较固定。友元函数可以访问私有成员,所以友元函数也能实现运算符重载,本例程使用成员函数进行运算符重载。
运算符重载的语法:
返回值类型 类名 :: operator op (参数)(operator是运算符重载关键字,op是要重载的运算符。)
后置---与前置--的区分方式在于后置--有int占位参数(利用C++函数重载的特性)
int Cat::operator-(Cat *cat)//- 运算符重载
int Cat::operator--() //前置-- 运算符重载
int Cat::operator--(int) //后置-- 运算符重载(使用占位参数说明是后置运算符重载)
一元重载:
个人理解是操作的对象只有一个,前置--和后置--属于一元重载,在重载函数实现中使用this指针既可以操作相应的成员
后置-- 和 前置-- 函数名是一样的。不同的是后置运算符重载有一个占位传参,这是编译器分辨这是前置还是后置运算符重载的标志。
二元重载:
操作对象有两个,‘-’ 运算符重载属于二元重载。
例如:
50 int Cat::operator-(Cat *cat)//- 运算符重载
51 {
52 cat->HP -= this->force_value;
53 if(cat->HP < 0)
54 cat->HP = 0;
55 cout<<this->name<<" hit - > "<<cat->name<<endl;
56 return cat->HP;
57 }
a-b;
此时在函数实现中,this指针操作的变量属于a,b则作为重载函数的传参。
2.友元函数
友元函数就是可以操作对象私有属性的函数。只要在类的定义中声明即可。
使用 friend 关键字,这个函数不是这个类的成员函数而是一个全局函数,可以通过传入参数cat来操作其私有成员,如果不是友元函数就算传入对象也不能操作其私有成员。
3.静态成员变量
静态成员变量是一个类所有对象共享的参数(个人理解成一个类的全局变量),本例程中Cat::food 就是静态成员变量,黑猫和白猫调用eat_food函数是两个不同对象操作了food成员,food减少了两次。
静态成员的定义:
1.先在定义类的时候声明
2.在C文件中给一个初始值
访问静态成员可以使用以下两种方法:
例:
Cat a("a");
a.food = 100;
Cat::food = 100;
4.new / delete 关键字和 malloc / free函数的区别
在本次例程中使用了两种创建对象的方法
使用new产生的是一个指针,之后操作white都是使用指针操作。
white是指针,使用前置-- 要先解引用(*white),如果没有解引用指针white就指到天南地北去了。
new创建的对象将分配堆的内存,与malloc一样。new也可以用于创建数组,变量等数据结构,malloc能做的事情new都能做。
malloc和new的那些事:
1.都是分配堆内存,使用完毕后需要释放
2.如果分配基础数据结构(暂时实验了除了类之外),malloc/free 、new/delete是可以互换的。即new出来的变量可以使用free释放,malloc的变量可以使用delete释放
3.分配类时,new将会调用构造函数,delete调用析构函数,所以创建类的时候不能使用malloc和free。
---恢复内容结束---