面向对象
-------------简单的事情重复做,重复的事情用心做,用心的事情坚持做(老九君)---------------
Tips:
-
类成员:变量 和 函数 均为成员
-
.h中声明类,.cpp文件中实现类
-
.hpp 一般包含实现的内联函数,用于模版类声明与实现共存的情况;建议只要不是纯模版,使用.h 作为头文件, .cpp 作为函数的实现文件
-
对象声明:LandOwnerV1 landOwner1; // 声明了一个LandOwner1类型对象landowner1
-
构造函数调用,对于无参构造函数不能加括号,因为c++会将其视为函数声明,如int test()
-
定义 对象、对象指针
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
ListNode dummy(0, head);
ListNode* dummy_p = new ListNode(0, head);
1. 面向对象 概况
面向对象编程 (oop: object oriented programming)–基于对象的概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界;涉及构建相应的软件系统(模拟现实)
NOTE:面向对象不是某一种语言的特性,而是一种编程思想。对象:有 数据 和 容许的操作 组成的封装体,与客观实体有直接的对应关系(属性和方法的集合)
面向对象 Vs 面向过程 (举个栗子)斗地主游戏的开发
- 面向过程:一步一步来,很多很多的过程函数:开始游戏-洗牌-发牌-显示手牌…-输出结果。
- 面向对象:
- 游戏参与者,行为模式是相同的–玩家对象,相同的属性和行为;
- 进行游戏的场景–牌桌对象,负责现实游戏的界面及内容;
- 游戏规则系统–裁判对象,负责判定牌面、输赢;
1.面向过程:首先考虑要遵循的步骤,然后考虑如何表示这些数据。面向过程代码超过10W行就会难管理,原来有因为飞机控制程序中一个",“写成”."号造成的空难。
2.面向过程:首先会考虑数据,包括数据的表示和数据的使用
2. 类、对象 class、struct
面向对象编程的流程:抽象 -> 用类封装
- 抽象:从具体事物中抽取共同的本质特征(处理复杂问题的技巧–简化、抽象)
- 用类封装:将抽象转换为用户定义类型的工具,将 数据 和 操作数据的方法 组合成一个整体。
(抽象)地主对象:外表特征--胖,留两撇胡子,两颗大金牙;行为特点--先出牌,多摸三张牌
(用类封装)地主类:
成员变量:名称、积分、手牌
成员函数:摸牌、出牌、产看积分
类和对象的关系:类实例就是一个对象;对象集合就是类,(或者说)类就是对象模版,
类的声明:使用class/struct 关键字声明
class 类名{}; // class声明的类 默认成员是私有的,推荐使用class声明类;
struct 类名{}; // struct声明的类 默认成员是共有的,struct声明结构,只包含数据POD,老式数据
c/c++ pod类型介绍 plain old data
地主类 - 类与对象 声明、实现
// 类、对象demo1. LandOwnerV1.cpp 文件中既声明又实现,main.cpp文件中调用
// 类、对象demo1. LandOwnerV1.cpp 地主类的声明、实现
#include <iostream>
using namespace std;
class LandOwnerV1 {
private:
string name; // 名称
long score; // 积分
int cards[20]; // 手牌数组
public :
LandOwnerV1() {}; // 默认构造函数
~LandOwnerV1() {}; // 默认析构函数
void TouchCard(int CardCount) { // 暂时省略函数实现
cout << name << "摸了" << CardCount << "张牌" << endl;
}
void ShowScore() {
cout << name << "当前的积分为:" << score << endl;
}
};
// 类、对象demo1. mian.cpp 地主类的调用
#include "LandOwnerV1.cpp"
int main() {
LandOwnerV1 landOwner1; // 声明了一个LandOwner1类型的对象landowner1
// landOwner1.cards[0] = 0; // 报错:'cards' is a private member of 'LandOwnerV1' ,调用对象成员, 不能直接使用对象的私有成员
landOwner1.TouchCard(100);
return 0;
}
// 类、对象demo1. 运行main.cpp 输出
摸了100张牌
// 类、对象demo2. LandOwnerV2.h中声明,LandOwnerV2.cpp中实现,main.cpp文件中调用
// 类、对象demo2. LandOwnerV2.h 地主类的声明
#include <iostream>
using namespace std;
class LandOwnerV2 {
private:
long score; // 积分
int cards[20]; // 手牌数组
public :
string name; // 名称
LandOwnerV2(); // 构造函数声明
~LandOwnerV2(); // 析构函数声明
void TouchCard(int); // 声明摸牌函数
void PlayCard(int); // 声明出牌函数
void ShowScore(); // 声明产看积分函数
};
// 类、对象demo2. LandOwnerV2.cpp 地主类的实现
#include <iostream>
#include "LandOwnerV2.h"
using namespace std;
LandOwnerV2::LandOwnerV2() {
// ctor(constructor)
}
void LandOwnerV2::TouchCard(int CardCount) {
cout << name << "摸了" << CardCount << "张牌" << endl;
}
void LandOwnerV2::ShowScore() {
cout << name << "当前的积分为:" << score << endl;
}
LandOwnerV2::~LandOwnerV2() {
// dtor
}
// 类、对象demo2. mian.cpp 地主类的调用
#include "LandOwnerV2.h" // 关注.h 文件
using namespace std;
int main() {
LandOwnerV2 landowner2;
landowner2.name = "小明";
//landowner2.TouchCard(20); // 成员函数没有调用成功
cout << landowner2.name << endl;
return 0;
}
3. 访问修饰符 public、private、protected
类成员: 变量 和 函数 均为成员, 不同访问修饰符下成员具备有不同的被访问权限:
- public: 修饰的成员 在任意地方都可以访问
- private: 修饰的成员 只能在类中或者友元函数中访问, 私有属性可以在名字前面加一个_
- protected: 修饰的成员 可以在类中函数、子类函数、友元函数中访问
访问修饰符 放在类声明中,使用 关键字+冒号 的形式表明成员的访问权限,无访问修饰默认为private。
class 类名{
修饰符:
成员类标;
};
封装: 数据隐藏,不希望别人随意操作, 使用 方法 来实现对成员变量操作的封装。
地主类 - 成员 访问、修改
// 类、对象demo3. 访问修饰符的实验。外部直接修改成员变量,不安全 (引出demo4封装的概念)
// 类、对象demo3. LandOwnerv3.h 文件, Created by 陈莹莹 on 2021/1/28.
#include <iostream>
#ifndef HELLOWORLD_LANDOWNERV3_H
#define HELLOWORLD_LANDOWNERV3_H
using namespace std;
class LandOwnerv3 {
int cards[20]; // 手牌数组
public :
string name;
long score; // 积分
LandOwnerv3(); // 构造函数声明, 没有返回值
~LandOwnerv3(); // 析构函数声明
void TouchCard(int); // 声明摸牌函数
void PlayCard(int); // 声明出牌函数
void ShowScore(int); // 声明产看积分函数
};
#endif //HELLOWORLD_LANDOWNERV3_H
// 类、对象demo3. LandOwnerv3.cpp 文件, Created by 陈莹莹 on 2021/1/28.
#include <iostream>
#include "LandOwnerv3.h"
using namespace std;
LandOwnerv3::LandOwnerv3() {
//ctor
}
void LandOwnerv3::ShowScore(int score) {
cout << name << "当前的积分为:" << score << endl;
}
LandOwnerv3::~LandOwnerv3() {
// dtor
}
// 类、对象demo3. mian.cpp 文件
#include <iostream>
#include "LandOwnerv3.h"
using namespace std;
int main(){
LandOwnerv3 landOwner3; // 访问修饰符的实验
landOwner3.name = "巴依老爷";
landOwner3.score = 100; // 修改地主积分,非私有成员,会被直接修改
landOwner3.ShowScore(landOwner3.score);
return 0;
}
// 类、对象demo3. 运行main.cpp 输出
巴依老爷当前的积分为:100
demo3中操作使得大家可以随意修改score,有一些不合理的积分就会出现。为了解决积分被赋值为不合理的情况,需要将成员变量score进行封装。 使用方法 来实现对成员的封装,数据隐藏、不希望别人随意操作。成员变量常用封装方法get()、set()
// 类、对象demo3改进. 访问修饰符的实验。使用 封装 防止直接修改成员变量
// 类、对象demo3改进. LandOwnerv3.h 文件 Created by 陈莹莹 on 2021/1/28.
#include <iostream>
#ifndef HELLOWORLD_LANDOWNERV3_H
#define HELLOWORLD_LANDOWNERV3_H
using namespace std;
class LandOwnerv3 {
long score; // 积分
int cards[20]; // 手牌数组
public :
string name;
LandOwnerv3(); // 构造函数声明, 没有返回值
~LandOwnerv3(); // 析构函数声明
void TouchCard(int); // 声明摸牌函数
void PlayCard(int); // 声明出牌函数
void ShowScore(); // 声明产看积分函数
void SetScore(long lScore) { // 定义成内联函数即可 (?)
if(lScore < 0) { // 通过条件判断封装了score的赋值过程
score = 0;
} else {
score = lScore;
}
}
};
#endif //HELLOWORLD_LANDOWNERV3_H
// 类、对象demo3改进. LandOwnerv3.cpp 文件 Created by 陈莹莹 on 2021/1/28.
// ........ 如 '类、对象demo3'
// 类、对象demo3改进. mian.cpp 文件
#include <iostream>
#include "LandOwnerv3.h"
using namespace std;
int main(){
LandOwnerv3 landOwner3;
landOwner3.name = "巴依老爷";
landOwner3.SetScore(-100); // 修改地主积分
landOwner3.ShowScore();
return 0;
}
// 类、对象demo3改进. 运行main.cpp 输出
巴依老爷当前的积分为:0
// 类、对象demo4. 访问修饰符的实验。 进一步封装:设置/获取名字,修改积分(版本4)
// LandOwnerv41.h 文件 Created by 陈莹莹 on 2021/1/29.
#ifndef HELLOWORLD_LANDOWNERV41_H
#define HELLOWORLD_LANDOWNERV41_H
#include <iostream>
using namespace std;
class LandOwnerv41 {
long score; // 积分
int cards[20]; // 手牌数组
string name;
public:
LandOwnerv41(); // 构造函数声明, 没有返回值
~LandOwnerv41(); // 析构函数声明
void TouchCard(int); // 声明摸牌函数
void PlayCard(int); // 声明出牌函数
void ShowScore(); // 声明产看积分函数
void SetScore(long lScore){
if(lScore < 0) {
score = 0;
} else {
score = lScore;
}
}
string GetName() {
return name;
}
void SetName(string lName) {
name = lName;
}
};
#endif //HELLOWORLD_LANDOWNERV41_H
// 类、对象demo4. LandOwnerv41.cpp 文件 Created by 陈莹莹 on 2021/1/29.
#include "LandOwnerv41.h"
#include <iostream>
using namespace std;
LandOwnerv41::LandOwnerv41() {
// ctor
}
void LandOwnerv41::ShowScore(){
cout << name << "当前的积分为:" << score << endl;
}
LandOwnerv41::~LandOwnerv41() {
// dtor
}
// 类、对象demo4. mian.cpp 文件
#include <iostream>
#include "LandOwnerv41.h"
using namespace std;
int main(){
LandOwnerv41 landOwner4;
landOwner4.SetName("巴依老爷");
cout << landOwner4.GetName() << endl;
landOwner4.SetScore(-100);
landOwner4.ShowScore();
return 0;
}
4. 构造函数(重点)
构造函数:(给编译器看)编译器在对象被创建时,为对象分配内存空间,并自动调用构造函数以完成 成员初始化。
KeyPoint:构造函数与类同名,没有返回值,种类如下:
- 默认构造函数(无参数构造函数)
- 一般构造函数(重载构造)
- 拷贝构造函数
- 转换构造函数
- 移动构造函数
地主类 - 默认构造(无参构造)
默认构造函数:一个类必有构造函数,即便没有显式定义构造函数,编译器会创建一个默认构造函数,具体形式如下:
ClassName() {}; // 方式1:xxsx
LandOwnerV4() = default; // 方式2:显式写法
- 如果创建的类中未书写任何构造函数,系统会自动生成默认的无参构造函数(函数为空)按照如下规则初始化数据乘员:
a. 存在类内初始值,则用该初始值初始化乘员
b. 否则使用默认初始化该成员 - 如果书写了构造函数,系统不会自动生成默认构造函数,如果希望有一个这样的无参数构造函数,需要自己显示书写LandOwnerV4() = default;
struct ListNode() {
int val = 0;
ListNode *next = nullptr; // 类内初始值 初始化成员
ListNode(int x) : val{x}, next(nullptr) {} // 初始值参数列表 初始化成员
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
note1: 默认构造 这里又称为 无参数构造函数, 其实是不同通过传参列表 确定成员变量的值
note2: 调用无参构造函数,其无参数,不用写(), 否则会被认为是函数声明。
// 类、对象demo4改进. 演示默认构造函数,使用无参构造函 初始化 成员变量
// 类、对象demo4改进. LandOwnerv41.h 文件
// ........ 如'类、对象demo4'
// 类、对象demo4改进. LandOwnerv41.cpp 文件 Created by 陈莹莹 on 2021/1/29.
#include "LandOwnerv41.h"
#include <iostream>
#include <memory.h>
using namespace std;
LandOwnerv41::LandOwnerv41() {
cout << "LandOwnerV41的无参数构造函数(默认构造)被调用!" << endl;
name = "默认地主";
score = 0;
memset(cards, 0, sizeof(cards)/sizeof(cards[0])); //将用户的手牌数组初始化为0
cout << "初始化的结果如下:" << endl;
cout << "名字:" << name << endl;
cout << "积分:" << score << endl;
cout << "手牌数组:" ;
for(int i=0; i < sizeof(cards)/sizeof(cards[0]); i++) {
cout << cards[i] << "\t";
}
cout << endl;
}
void LandOwnerv41::ShowScore() {
cout << name << "当前的积分为:" << score << endl;
}
LandOwnerv41::~LandOwnerv41() {
//dtor
}
// 类、对象demo4改进. mian.cpp 文件
#include "LandOwnerv41.h"
using namespace std;
int main(){
LandOwnerv41 landOwnerv4; // 调用无参构造函数,其无参数,所以不用写()
LandOwnerv41 landOwnerv4(); // 会被认为是函数声明,不会实现无参构造函数调用,而不会有任何输出。
return 0;
}
// 类、对象demo4改进. 运行main.cpp 输出 // 手牌数组的初始化不是全为0?
LandOwnerV41的无参数构造函数(默认构造)被调用!
初始化的结果如下:
名字:默认地主
积分:0
手牌数组:0 0 0 0 0 0 0 0 -375207560 32766 -375207584 32766 0 1 0 0 0 0 0 0
一般构造函数 (重载构造)(带参构造函数),语法:
类名::构造(类型1 参数1, 类型2 参数2, ....){
// 相关初始化方法
}
学生类 - 一般构造函数(初始值参数列表)、堆内存对象、栈内存对象
一般构造函数:推荐使用 初始值列表的写法,直接初始化数据乘员,而非对数据成员直行赋值操作。( 类、对象demo5中有两种方式写法的对比), 不同参数列表的构造函数,是函数重载的表现。
- 栈内存中的对象(类似于函数声明)–具体对象由系统创建并释放,不用担心内存泄露。
声明周期只在声明区域的大括号内。
优点 - 栈内存优势 存取速度快(仅次于寄存器),缺点栈内存中的数据大小生存期是确定的,缺乏灵活性。
Student stu; // 自定义类型名 对象名;
- 堆内存中的对象(需要new关键字)p_stu1是指针,必须使用delete释放
优点:使用灵活可以赋给全局变量,可以把对象作为函数的返回值
Student *p_stu1 = new Student();
Student *p_stu2 = new Student();
auto *p_stu3 = new Student(); // auto 自动类型判断,不推荐使用,sizeof 会报错
NOTE: 类对象推荐放在堆内存中,即使用new来创建对象。
C++ new用法 (结论:别使用不带括号的new。)
Tips: 如果构造函数中只有一个参数,且单参数构造函数只有一个,可以直接使用赋值操作进行初始化
// 类、对象demo5. 学生类 - 堆内存对象、栈内存对象
// 类、对象demo5. Student.h 文件 Created by 陈莹莹 on 2021/2/2.
#ifndef HELLOWORLD_STUDENT_H
#define HELLOWORLD_STUDENT_H
#include <iostream>
using namespace std;
class Student {
private:
string m_name;
string m_desc;
int m_age;
public:
Student(); // 默认构造函数
Student(string, string);
~Student();
void showInfo();
};
#endif //HELLOWORLD_STUDENT_H
// 类、对象demo5. Student.cpp 文件 Created by 陈莹莹 on 2021/2/2.
#include <iostream>
#include "Student.h"
using namespace std;
Student::Student() {
cout << "默认构造函数" << endl;
}
// 语法正确 但是 草率,通过赋值操作实现成员函数值的设置
//Student::Student(string name, string desc) {
// m_name = name;
// m_desc = desc;
// cout << "设置带参构造" << endl;
//}
// 推荐使用:初始值参数列表 的写法
Student::Student(string name, string desc):m_name(name), m_desc(desc) {
cout << "设置带参构造" << endl; // 其实应该是一个空函数体
}
void Student::showInfo() {
cout << m_desc << m_name << endl;
}
Student::~Student() {
}
// 类、对象demo5. mian.cpp 文件
#include <iostream>
#include "Student.h"
using namespace std;
int main(){
Student stu1; // 演示构造函数,实质就是函数重载
Student stu2("马化腾","普通家庭"); // 在栈内存中直接分配空间,速度块
// Student stu4 = 45 // 如果构造函数中只有一个参数,且单参数构造函数只有一个,可以直接使用赋值操作进行初始化
stu2.showInfo();
Student * stu5 = new Student("杰克马", "毁创阿里"); // 使用new分配堆内存, 学生类指针
stu5 ->showInfo(); // 类指针访问方法要使用 ->
return 0;
}
// 类、对象demo5. 输出结果
默认构造函数
设置带参构造
普通家庭马化腾 // stu2.showInfo(); 的输出
设置带参构造
毁创阿里杰克马 // stu5 ->showInfo(); 的输出
5. 析构函数
析构函数:特殊成员函数,对象销毁时自动调用,用来完成清理工作。
语法:每个类只能有一个析构函数、函数名为‘~类名’、没有参数
析构函数体:需要释放(delete)掉在构造函数中手动分配(new)的空间(对象内部的成员变量)。
- 析构函数用来释放对象使用的资源,并销毁对象的非static数据成员。
- 无论何时一个对象被销毁,都会自动调用析构函数(隐式析构)。
栈内存对象:在栈内存中构造的对象,在栈区(mian函数)销毁时,类对象会被自动销毁。
堆内存对象:在堆内存中构建的类对象,需要手动释放。
学生类 - 析构函数
类对象推荐放在堆内存中,即使用new来创建对象。
// 类、对象demo6. 学生类 - 析构函数演示(构造函数中未new资源)
// 类、对象demo6. Student.h 文件
// ........ 如'类、对象demo5'
// 类、对象demo6. Student.cpp 文件 Created by 陈莹莹 on 2021/2/2.
#include <iostream>
#include "Student.h"
using namespace std;
Student::Student() {
cout << "默认构造函数" << endl;
}
//Student::Student(string name, string desc) {
// // 参数列表不同,函数重载
// m_name = name;
// m_desc = desc;
// cout << "设置带参构造" << endl;
//}
//初始化参数列表的写法,和上面的带参数构造方法完全相同
Student::Student(string name, string desc):m_name(name), m_desc(desc) {
cout << "设置带参构造" << endl;
};
void Student::showInfo() {
cout << m_desc << m_name << endl;
}
Student::~Student() {
cout << m_name << "被释放" << endl;
}
// 类、对象demo6. mian.cpp 文件
#include <iostream>
#include "Student.h"
using namespace std;
int main(){
Student stu1;
Student stu2("马化腾","普通家庭"); // 在栈内存中直接分配空间,速度块
// Student stu4 = 45 // 如果构造函数中只有一个参数,且单参数构造函数只有一个,可以直接使用赋值操作进行初始化
stu2.showInfo();
// 学生指针类型, 使用new 分配内存空间
Student * stu5 = new Student("杰克马", "毁创阿里"); // 使用new分配堆内存, 学生类指针
// 类指针访问方法要使用 ->
stu5 ->showInfo();
return 0;
}
// 类、对象demo6. 输出结果
默认构造函数 // stu1
设置带参构造 // stu2
普通家庭马化腾 // stu2.showInfo()
设置带参构造 // stu5
毁创阿里杰克马 // stu5.showInfo()
杰克马被释放 // main函数执行结束,自动释放 杰克马
马化腾被释放 // main函数执行结束,自动释放 马化腾
被释放 // main函数执行结束,自动释放 stu1
6. this指针(重点)
(类似于于python中的self,在python中显式传递self参数)
每个成员函数(包括构造函数和析构函数)都有一个this指针。this指针指向调用对象,可以通过this关键字访问当前对象的成员。this 在成员函数执行前就已经创建,在析构函数之后被销毁。
- 访问成员变量:this -> 成员名;
- 访问成员函数:this -> 函数名();
- this 指针的类型为*const,为右值;(可以赋值)
- this指针本身不占用大小,并不是对象的一部分,用sizeof 测不出来大小
- this指针作用域在成员函数内部;
- this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递,编写者不能显式传递。
- 在类非静态成员函数中才可以使用this指针,其他任何函数都不可以(static是先于类实例存在的,this还没有创建)
学霸类 - 返回对象的引用
// 类、对象demo7. 学生类 -
// 类、对象demo7. Student.h Created by 陈莹莹 on 2021/2/2.
#ifndef HELLOWORLD_STUDENT_H
#define HELLOWORLD_STUDENT_H
#include <iostream>
using namespace std;
class Student {
private:
string m_name;
string m_desc;
int m_age;
float *scores; // 学生的分数数组,在某个构造的时候进行初始化
int scoreCount; // 学生成绩的个数
public:
Student(); // 默认构造函数
Student(string, string);
~Student();
void showInfo();
void InitScores(); // 初始化学生的成绩数组,默认分配一个元素空间
void AddScore(float score);
// 返回值是引用时,是非常危险的。this可以直接修改属性,建议在函数声明处加一个const, 限制在该函数内部不能通过this指针修改属性,太麻烦了,要该的地方太多了 todo
Student & GetSuperScholars(Student &); //返回学霸对象 todo
float GetTotal(); // 参数处加const 保证不对该参数进行修改。todo
string GetName() {return m_name;}
};
#endif //HELLOWORLD_STUDENT_H
// 类、对象demo7. Student.cpp Created by 陈莹莹 on 2021/2/2.
#include <iostream>
#include "Student.h"
using namespace std;
Student::Student() {
cout << "默认构造函数" << endl;
InitScores();
}
Student::Student(string name, string desc):m_name(name), m_desc(desc) {
cout << "设置带参构造" << endl;
InitScores();
};
void Student::InitScores() {
this -> scores = new float [1]; // 构造函数中 new 出来的成员变量,析构函数中需要释放
this -> scoreCount = 1;
}
void Student::showInfo() {
cout << m_desc << m_name << endl;
for(int i = 0; i < scoreCount-1; i++){
cout << this->scores[i] << "\t";
}
cout << endl;
}
void Student::AddScore(float score) {
// 1. 创建一个新数组,分配scoreCount+1 个空间
// 2. 复制愿数组中的内容到新数组中
// 3. scoreCount++
// 4. scores指向新数组
this -> scores[this->scoreCount - 1] = score; // 初始化的时候分配了空间,未赋值,现在赋后拷贝到空间增加了的内存中
float *newScores = new float [scoreCount + 1];
float *oldScores = scores;
memcpy(newScores, scores, sizeof(float) * scoreCount);
scoreCount++;
scores = newScores;
delete oldScores; // 删除原来的指针
}
Student& Student::GetSuperScholars(Student &otherstu){
// otherstu 要对比的另一学生对象
// 返回总分比较大的那个学生对象
// 分别计算两个学生的总分
if(this->GetTotal() > otherstu.GetTotal()){
return *this; // 指针, * 得引用。
} else {
return otherstu; // 直接返回引用
}
}
float Student::GetTotal() {
float sum = 0;
for(int i = 0; i < scoreCount; i++){
sum += scores[i];
}
return sum;
}
Student::~Student() {
cout << m_name << "被释放" << endl;
delete this -> scores;
}
// 类、对象demo7. mian.cpp
#include <iostream>
#include "Student.h"
using namespace std;
int main(){
Student *ptr_stu1 = new Student("迪丽热巴","微胖女孩"); // 堆内存对象
ptr_stu1->AddScore(78.9);
ptr_stu1->AddScore(77.9);
ptr_stu1->AddScore(72.9);
ptr_stu1->AddScore(79.9);
ptr_stu1->AddScore(800);
ptr_stu1->showInfo();
Student stu2("刘强东","不爱美人"); // 栈内存对象
stu2.AddScore(78.9);
stu2.AddScore(77.9);
stu2.AddScore(72.9);
stu2.AddScore(79.9);
stu2.AddScore(90);
stu2.showInfo();
Student &scholar1 = stu2.GetSuperScholars(*ptr_stu1); //返回迪丽热巴的引用,
Student &scholar2 = ptr_stu1->GetSuperScholars(stu2); //返回迪丽热巴的引用
cout << "学霸是" << scholar1.GetName() << "\t" << scholar2.GetName() << endl;
delete ptr_stu1; // scholar2 栈内存中定义的,main 结束后会自动释放
return 0;
}
// 类、对象demo7. 输出结果
设置带参构造
微胖女孩迪丽热巴
78.9 77.9 72.9 79.9 800
设置带参构造
不爱美人刘强东
78.9 77.9 72.9 79.9 90
学霸是迪丽热巴 迪丽热巴
迪丽热巴被释放
刘强东被释放
小结:类就是自己定义的数据类型,对象就是变量