本文仅用于记录自己在奇牛软件学习的过程,并对自己起到一个督促性的作用。(目前正在学习C/C++入门的基础语法篇)
作为一名非计算机专业的大龄工科生,我正踏上转向编程(特别是图形学领域)的旅程。在这个过程中,C++成为了我的主要工具。回顾过去一年,我时断时续地学习C++,却发现自己经常在重复相同的概念,没有明确的学习方向,常感到知识点零散且琐碎。
一次偶然的机会,我在B站上看到了Rock老师和学生的交流视频,被他负责任的态度所吸引。在与他简短的沟通后,我决定加入奇牛软件学院。通过学院的项目实践,我希望能够以更系统、实用的方式来掌握C++。同时,我也期待对计算机科学有更深入的理解,尤其是数据结构和算法。
我设定了一个明确的目标:希望在未来一年里,在技能和知识上实现显著的提升。我希望能够将过去零散的学习经历转化为对C++的全面而连贯的理解,为我明年的校园招聘打下坚实的基础。
首先十分感谢Rock老师向我介绍写博客这种方式来记录我的学习,看到有这么多浏览量心里又开心又惶恐,感谢大家围观我这么一个大龄废物的成长史,也希望我可以一直坚持下去,期待大家一起不断变强,在cpp的道路上越走越顺~~加油!
目录
2.1之前的课程完成了项目的基本构建,基本的项目优化迭代思想如下:
2.3.1 作业 no.1 (对于文件读写以及iostream的训练)
昨天学习记录如下:
#Day 01 Mon
2024-01-15 18:33:42: Total study time: 00:38:57
2024-01-15 19:06:02: Total study time: 00:16:49
2024-01-15 19:26:28: Total study time: 00:20:01
2024-01-15 20:35:16: Total study time: 01:00:18
2024-01-15 20:45:23: Total study time: 00:10:05
2024-01-15 21:50:31: Total study time: 00:49:38
2024-01-15 23:00:57: Total study time: 01:09:23
进展如下(完成视频观看和代码练习,最终代码全部运行成功)
学到的重点内容有:
1.流操作对象
-
注意文件的打开和关闭一定要成对出现。
-
文件流的状态检查:(常用操作)
-
.is_open()
文件流对象打开成功与否的判断 -
.eof()
文件结尾标识符
-
-
文件流的定位方法:
-
seekg(offset, relative_location)
(beg
cur
end
) :基于相对位置和偏移量来放置输入流的cursor -
tellg()
用于计算cursor 到文件头的字符长度,即当前流的位置,可以应用于文件的字符数量计算 -
seekp()
用于调整输出文件流的cursor位置实现文件写的自定义 -
下面三个函数分别解释了以上两种方法的使用
-
#include <iostream> #include <fstream> void checkSeekg(){ std::ifstream ifs; ifs.open("/home/herryao/rest.sh"); if(!ifs.is_open()){ return; } ifs.seekg(-50, ifs.end); std::string line; while(!ifs.eof()){ getline(ifs, line); std::cout << line << std::endl; } ifs.close();ekp(4, ofs.beg) } //for exemplify the usage of the tellg() //from a file extract the size of the file [[nodiscard]]long long checkTellg(const char* fileName){ std::ifstream ifs; ifs.open(fileName); if(!ifs.is_open()){ return 0; } //place the cursor to the end of the file ifs.seekg(0, ifs.end); long long ret = ifs.tellg(); ifs.close(); //return the length return ret; } void checkSeekp(){ std::ofstream ofs; ofs.open("check.txt"); if(!ofs.is_open()){ return; } ofs << "123456789"; //123456789 // ^ ofs.seekp(4, ofs.beg); ofs << "ABC"; ofs.close(); }
-
2. 关于流对象的项目实战,对于相亲平台项目的优化
2.1之前的课程完成了项目的基本构建,基本的项目优化迭代思想如下:
-
建立两个男人女人类,通过面向对象的思想:
-
赋予其各自特性(private):
姓名
,年龄
,颜值(女)
,工资(男)
-
赋予其成员方法 <对外的接口 >(public):
获取姓名
,获取年龄
,获取颜值
,获取工资
,个人描述
-
建立有参数构造函数,分别初始化各自的成员变量
-
两个
静态成员函数
在两个类中分别用于输入新加入的男人女人 -
两个返回值为
bool
的函数用于判断是否对对方满意(基于一个简单的运算即分别给颜值(男)和工资(女)一个系数用于计算对方的平分并与自己的属性进行比较,不低于自己属性的视为满意返回true
, 反之亦然)
-
-
发现男人女人类中有很多的成员变量成员方法是重复的, 采用继承特性尽量避免重复
-
建立一个父类Person,包含二者的共有属性,
姓名
和年龄
-
包含二者的共有方法,
获取姓名
,获取年龄
并直接给出定义 -
由于
个人描述
这个方法在不同的类型下会有不同的实现方法,因此给这个方法一个纯虚设定,由各自派生类重写 -
构造函数则传入
姓名
,年龄
这两个变量对Person中的成员变量进行初始化 -
在
main
函数之实现一个自动配评分的函数
以上实现的代码如下:
-
Person基类
头文件
:
/* * Created by herryao on 1/13/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #ifndef PROJECT01_PERSON_H #define PROJECT01_PERSON_H #include<string> class Person { public: Person(int age, std::string name); virtual ~Person(); [[nodiscard]] int getAge()const; [[nodiscard]] std::string getName()const; [[nodiscard]] virtual std::string description()const = 0; //protected: private: int age_; std::string name_; }; #endif //PROJECT01_PERSON_H
-
Person基类
源文件
:
/* * Created by herryao on 1/13/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #include "Person.h" int Person::getAge() const { return age_; } std::string Person::getName() const { return name_; } Person::~Person() = default; Person::Person(int age, std::string name) { this->age_ = age; this->name_ = std::move(name); }
-
Boy 类
头文件
:
/* * Created by herryao on 1/12/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #ifndef PROJECT01_BOY_H #define PROJECT01_BOY_H #include<iostream> #include<string> #include <vector> #include<sstream> #include"Girl.h" #include"Person.h" #define SALARY_FACTOR 0.006 class Girl; class Boy: public Person{ public: Boy(); Boy(int age, std::string name, int salary); ~Boy()override; [[nodiscard]]int getSalary()const; [[nodiscard]]bool satisfaction(const Girl& g) const; [[nodiscard]]std::string description() const override; static void inputBoys(std::vector<Boy> & boys); private: int salary_; }; #endif //PROJECT01_BOY_H
-
Boy类
源文件
:
/* * Created by herryao on 1/12/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #include "Boy.h" #include <utility> Boy::Boy() : Person(18, "unknown"){ this->salary_ = 0; } Boy::Boy(int age, std::string name, int salary): Person(age, std::move(name)) { this->salary_ = salary; } Boy::~Boy() = default; int Boy::getSalary() const { return salary_; } bool Boy::satisfaction(const Girl &g) const { //to do if(g.getBeauty() >= (salary_*SALARY_FACTOR>100 ? 100 : salary_*SALARY_FACTOR)){ return true; } return false; } std::string Boy::description() const { std::stringstream ret; //if the member variables are private instead of protected, it is invisible for the derived class //using the public interface is a good choice // ret << name_ << " male - salary(" << salary_ << ") - age(" << age_ << ") "; ret << getName() << " male salary(" << salary_ << ") age(" << getAge() << ")"; return ret.str(); //transfer to the string type } void Boy::inputBoys(std::vector<Boy> &boys) { int n = 1; int age, salary; std::string name; while(1){ std::cout << "please enter number: " << n << " Boy>> Age[end with 0]: "; std::cin >> age; if(age==0){ break; } std::cout << "please enter number: " << n << " boy>> name: "; std::cin >> name; std::cout << "please enter number: " << n << " boy>> salary: "; std::cin >> salary; boys.emplace_back(age, name, salary); } }
-
Girl 类
头文件
:
/* * Created by herryao on 1/12/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #ifndef PROJECT01_GIRL_H #define PROJECT01_GIRL_H #include<string> #include <sstream> #include <vector> #include "Boy.h" #include"Person.h" #define BEAUTY_FACTOR 100 class Boy; class Girl :public Person{ public: Girl(); Girl(int age, std::string name, int beauty); ~Girl() override; [[nodiscard]]int getBeauty()const; [[nodiscard]]bool satisfaction(const Boy& b) const; [[nodiscard]]std::string description() const override; static void inputGirls(std::vector<Girl> &girls); private: int beauty_; }; #endif //PROJECT01_GIRL_H
-
Girl 类
源文件
:
/* * Created by herryao on 1/12/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #include "Girl.h" #include <utility> Girl::Girl() : Person(18, "unknown"){ this->beauty_ = 0; } Girl::Girl(int age, std::string name, int beauty): Person(age, std::move(name)) { this->beauty_ = beauty; } Girl::~Girl() = default; int Girl::getBeauty() const { return beauty_; } bool Girl::satisfaction(const Boy &b) const { //to do if(b.getSalary() >= (beauty_*BEAUTY_FACTOR > 100 ? 100 : beauty_*BEAUTY_FACTOR)){ return true; } return false; } std::string Girl::description() const{ std::stringstream ret; //if the member variables are private instead of protected, it is invisible for the derived class //using the public interface is a good choice // ret << name_ << " female - beauty(" << beauty_ << ") - age(" << age_ << ") "; ret << getName() << " female beauty(" << beauty_ << ") age(" << getAge() << ")"; return ret.str(); //transfer to the string type } void Girl::inputGirls(std::vector<Girl> &girls) { int n = 1; int age, beauty; std::string name; while(1){ std::cout << "please enter number: " << n << " Girl>> Age[end with 0]: "; std::cin >> age; if(age==0){ break; } std::cout << "please enter number: " << n << " girl>> name: "; std::cin >> name; std::cout << "please enter number: " << n << " girl>> beauty: "; std::cin >> beauty; girls.emplace_back(age, name, beauty); } }
-
main.cpp
#include <iostream> #include "Boy.h" #include "Girl.h" #include <vector> void autoPair(const std::vector<Boy> &boys, const std::vector<Girl> &girls){ for(const auto& boy: boys){ for(const auto& girl: girls){ auto is_succeed = (boy.satisfaction(girl)&&girl.satisfaction(boy)); if(is_succeed){ std::cout << boy.description() << "<==>" << girl.description() << std::endl; } } } } int main() { std::vector<Girl> Gl; std::vector<Boy> Bl; Boy::inputBoys(Bl); Girl::inputGirls(Gl); autoPair(Bl,Gl); }
-
2.2 此次对于上次建立项目的提升及相关实现:
-
对于存入的会员每次登陆都需要重新输入,这很不方便,由此联想到所学的文件输入输出流,将所有信息保存到文件中并读取就可以解决这一问题
-
对于自动匹配函数,孤立于整个系统之外,这不符合面向对象编程封装的思想
encapsulation
, 最好将这一函数也一并封装起来
由此想到建立一个Database类来实现文件的读写和系统内会员的初始化,以及成员之间的自动匹配功能,当然具体实现下不仅限于这些功能
本次具体实现的Database的细节如下:
-
作为一个数据库,数据的存储是有必要的,且这些数据应当被保护起来,因此包含了两个vector 私有对象变量分别用于保存男人,女人对象
-
在项目启动过程应当有一个初始化功能(男女对象的初始化在此是分别进行的):
-
在项目启动时,应当自动读取数据存储文件,并以此来初始化相应的男人女人对象数据
-
当读取文件失败,这说明档案还未建立,这时应该要求用户分别输入相关人员的信息,写入至文件中并保存到成员变量
-
在这里建立了两个成员方法分别用于读取输入人员的信息(男人,女人)
-
这个初始化函数很复杂,这个项目的大部分时间都用在这个函数上了,还有一些操作系统和工具链的不匹配问题(博主用的是clion+ubuntu)具体可以看我的注释(仅为个人理解,写的很混乱.......)
-
-
Database的构造函数应当直接调用一个初始化函数对整个类内成员进行初始化
-
建立一个公有方法用于打印数据库内成员的信息,分别遍历保存男人女人的vector,然后分别调用他们个人描述的方法
-
最后基于实际项目的需求有添加了一个功能,即:
-
实现一个方法单独添加一个新人
-
将这个新人的信息添加到成员变量中并写入数据文件中
-
自动返回和这个人相匹配的所有人的信息
为此我使用了两个方法分别用于输入男人和女人,在保存到文件这一步骤中,我使用了多态的方法,用Person的引用调用不同的成员,并把其信息写入到文件中
-
-
将自动配对函数写入到Database中,这个没什么好说的,只是把传入参数变成了调用自己的成员变量,其余不变
具体实现只是添加了一个Database的类,原有类并没有进行修改
-
Database.h
/*
* Created by herryao on 1/15/24.
* Email: stevenyao@g.skku.edu
* Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL)
*/
#ifndef PROJECT01_DATABASE_H
#define PROJECT01_DATABASE_H
#include "Boy.h"
#include "Girl.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
class Database {
public:
Database();
void autoPair();
void print();
void init();
//add a new user and output the auto-pair result
void inputSingleBoy();
void inputSingleGirl();
private:
//information for all the people in system
std::vector<Boy> boys_;
std::vector<Girl> girls_;
//give a private accessing authority will be better for safety
void initBoys(const std::string& fileName);
void initGirls(const std::string& fileName);
static void saveBoys(const std::string& fileName, const std::vector <Boy>& boys);
static void saveGirls(const std::string& fileName, const std::vector <Girl>& girls);
//output the auto-pair result for a single user
static void saveSinglePerson(const Person& single, const std::string& file_name);
};
#endif //PROJECT01_DATABASE_H
-
Database.cpp
/*
* Created by herryao on 1/15/24.
* Email: stevenyao@g.skku.edu
* Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL)
*/
#include "Database.h"
void Database::autoPair() {
std::cout << "the result of the auto pair system" << std::endl;
for(const auto& boy: boys_){
for(const auto& girl: girls_){
auto is_succeed = (boy.satisfaction(girl) && girl.satisfaction(boy));
if(is_succeed){
std::cout << std::string(100,'=') << std::endl;
std::cout << boy.description() << "\n" << girl.description() << std::endl;
std::cout << std::string(100,'=') << std::endl;
}
}
}
}
void Database::init() {
//initialization for both from saved logs
initBoys("boys.txt");
initGirls("girls.txt");
}
void Database::initBoys(const std::string& fileName){
std::ifstream ifs;
ifs.open(fileName);
if(!ifs.is_open()){
ifs.close();
//if no file, enter a initialized data by user
std::cout << "============enter basic information for boys============" << std::endl;
Boy::inputBoys(this->boys_);
saveBoys(fileName,this->boys_);
return;
// ifs.close();
}
//position judgement there is problem
while(true){
int age, salary;
char name_buff[100];
std::string line;
getline(ifs, line);
if(ifs.eof()){
break;
}
//<cstdio>
//sscanf_s is suitable for windows vc++ while not suitable for clang++ or g++
//in g++ only the sscanf can be used, but the buffer memory should be enough
//problem comes from this line, so if reaching the eof(), simply break before this line will be the solution
int ret = sscanf(line.c_str(), "%s male salary(%d) age(%d)", name_buff, &salary, &age);
if(ret <= 0){
std::cout << "dataset for boy fails in matching the format" << std::endl;
exit(1);
}
std::string name(name_buff);
boys_.emplace_back(age, name, salary);
}
ifs.close();
}
void Database::initGirls(const std::string& fileName) {
std::ifstream ifs;
ifs.open(fileName);
if(!ifs.is_open()){
//if no file, enter a initialized data by user
ifs.close();
std::cout << "============enter basic information for girls============" << std::endl;
Girl::inputGirls(this->girls_);
saveGirls(fileName, this->girls_);
return;
}
while(true){
std::string line;
int age, beauty;
char name_buff[200];
//sscanf_s is suitable for windows vc++ while not suitable for clang++ or g++
//in g++ only the sscanf can be used, but the buffer memory should be enough
//problem comes from this line, so if reaching the eof(), simply break before this line will be the solution
getline(ifs, line);
if(ifs.eof()){
break;
}
int ret = sscanf(line.c_str(), "%s female beauty(%d) age(%d)", name_buff, &beauty, &age);
if(ret <= 0){
std::cout << "dataset for girl fails in matching the format" << std::endl;
exit(1);
}
std::string name{name_buff};
girls_.emplace_back(age, name, beauty);
}
ifs.close();
}
void Database::saveBoys(const std::string& fileName, const std::vector <Boy>& boys){
std::ofstream ofs;
ofs.open(fileName, std::ios::app);
if(!ofs.is_open()){
return;
}
for(const auto& boy: boys){
std::stringstream ret;
// ret << boy.getName() << "\t" << boy.getAge() << "\t" << boy.getSalary() << "\n";
ret << boy.description();
ret << std::endl;
ofs << ret.str();
}
//the file is not generated while the ofstream closed, why?
ofs.close();
}
void Database::saveGirls(const std::string& fileName, const std::vector <Girl>& girls){
std::ofstream ofs;
ofs.open(fileName, std::ios::app);
if(!ofs.is_open()){
return;
}
for(const auto& girl:girls){
std::stringstream ret;
// ret << girl.getName() << "\t" << girl.getAge() << "\t" << girl.getBeauty() << "\n";
ret << girl.description();
ret << std::endl;
ofs << ret.str();
}
ofs.close();
}
void Database::print() {
std::cout << "The information of boys: " << std::endl;
for(const auto& boy: boys_){
std::cout << boy.description() << "\t";
}
std::cout << "\nThe information of girls: " << std::endl;
for(const auto& girl: girls_){
std::cout << girl.description() << "\t";
}
std::cout << "\n";
}
Database::Database() {
init();
}
//different from rock, here we didn't pass one object, but use
// the temporary object and directly push it to the vector instead.
void Database::inputSingleGirl() {
int age, beauty;
std::string name;
std::cout << "please enter Age(girl)[end with 0]: ";
std::cin >> age;
if(age==0){
return;
}
std::cout << "please enter name: ";
std::cin >> name;
std::cout << "please enter beauty: ";
std::cin >> beauty;
Girl girl(age, name, beauty);
girls_.emplace_back(girl);
bool succeed = false;
for(const auto& boy: boys_){
succeed = (girl.satisfaction(boy)&&boy.satisfaction(girl));
if(succeed){
std::cout << boy.description() << std::endl;
}
}
if(!succeed){
std::cout << "no matched user found!" << std::endl;
}
saveSinglePerson(girl, "girls.txt");
}
void Database::inputSingleBoy() {
int age, salary;
std::string name;
std::cout << "please enter Age(boy)[end with 0]: ";
std::cin >> age;
if(age==0){
return;
}
std::cout << "please enter name: ";
std::cin >> name;
std::cout << "please enter salary: ";
std::cin >> salary;
Boy boy(age, name, salary);
boys_.emplace_back(boy);
bool succeed = false;
for(const auto& girl: girls_){
succeed = (girl.satisfaction(boy)&&boy.satisfaction(girl));
if(succeed){
std::cout << girl.description() << std::endl;
}
}
if(!succeed){
std::cout << "no matched user found!" << std::endl;
}
saveSinglePerson(boy, "boys.txt");
}
//we put the person saving use a static function, where the polymorphism is activated,
// using the virtual function description() from base class Person combined with the
// Person reference passing parameter.
void Database::saveSinglePerson(const Person &single, const std::string &file_name) {
std::ofstream ofs;
ofs.open(file_name, std::ios::app);
std::stringstream ret;
ret << single.description();
ret << std::endl;
ofs << ret.str();
}
-
新的main.cpp
#include <iostream>
#include "Boy.h"
#include "Girl.h"
#include <vector>
#include "Database.h"
/*
* how to implement the log system?
* using oop method
* design a new class achieving data saving
*
* Database class
* function:
* init(); //initialization with the log file reading
* autoPair();
* print(); //print all the information from the database
* data:
* vector<Boy> boys; // store all the information of boys
* vector<Girl> girls; // store all the information of girls
*
* */
int main() {
Database data;
data.print();
// data.autoPair();
data.inputSingleBoy();
data.print();
data.inputSingleGirl();
data.print();
return 0;
}
2.3 两个小作业:
2.3.1 作业 no.1 (对于文件读写以及iostream的训练)
-
要求1.:输入一个整数变量,如果输入非整数变量如 ‘a’, ‘b’ ......就会进入无限循环直到输入一个合法的数据, 当输入停止时输出到一个文件中,且每十个数字要重新换行继续执行
-
思路:这个项目考虑的是对于
std::cin
错误的纠正方法,以及输出流对象的训练 -
知识点:
-
std::cin
这个输入对象只要见到'\n'就会停止
-
std::cin.eof()
这个方法表示std::cin的终止,在vs中就等于ctrl+z
, 但是在clion
中实测不好用,博主在这个判断中用了输入数字为-1,(不严谨) -
std::cin.fail()
这个方法在std::cin
崩溃时会返回true
-
std::cin.clear()
用这个方法清除错误标志 -
std::cin.ignore(_count_, _character_)
这个方法输入两个参数,第一个是个数,第二个是休止符,在本次实战中运用了<limits>
库中的std::numeric_limits<std::streamsize>::max()
,这个方法返回的是cin中最大的缓存尺寸,即清除所有的缓存
-
-
-
要求2.:从刚才写好的文件中读取所有数据,求出其中的最大值最小值和平均数
-
思路:写一个文件读取函数把数据存起来,然后对数据进行处理
-
在这里Rock老师用了循环的方式(因为现在还没有到标准库的讲解阶段),我比较偷懒直接用了标准库中的实现 + vector的迭代器 + 匿名函数直接实现了,我觉得这种东西没什么优劣,像rock老师说的实现相同功能即可,但是这种茴香豆的写法,作为初学者我还是认为有必要多了解一下,大家见仁见智。
-
-
下面直接放上练习代码:
#include <iostream> #include <fstream> #include <limits> #include <vector> #include <algorithm> //input integer and save, while there is invalid input endless loop till valid, end with -1 void inputInt(){ std::ofstream ofs; ofs.open("number.txt"); int num; int count = 0; if(!ofs.is_open()){ std::cout << "fail in open the file!" << std::endl; exit(1); } while(true){ //enter a integer std::cout << "please enter one integer(-1 to quit): "; std::cin >> num; //ctrl + z == std::cin.eof() if(std::cin.eof() || num == -1){ break; } //if fail in entering >> 'a', 'b', ... while(std::cin.fail()){ std::cin.clear(); // clear the error signature //std::numeric_limits<std::streamsize>::max() >> maximum size of the iostream //delete everything in the buffer of iostream //std::cin ending with the '\n', ignore the characters till '\n' and including it. //std::cin.ignore(_count_, _character_); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cout << "Invalid input, please try again." << std::endl; std::cin >> num; } //out of the error, write the contents into the log file ofs << num << "\t"; if(((++count) %10) == 0){ ofs << "\n"; } } //out of the loop, should be close operation on the stream! ofs.close(); } //from the log read all the data and print the maximum, minimum as well as average values among them void dataLoader(){ std::ifstream ifs; ifs.open("number.txt"); if(!ifs.is_open()){ return; } std::vector<int> data; while(!ifs.eof()){ int temp; ifs >> temp; data.push_back(temp); } ifs.close(); int sum = 0; int num = 0; //standard library >> algorithm + vector iterator + lambda expression int max = *(std::max_element(data.begin(), data.end()));//return an iterator int min = *(std::min_element(data.begin(), data.end()));//return an iterator std::for_each(data.begin(), data.end(),[&sum,&num](int x){sum+=x; ++num;}); float ave = (float)sum/(float)num; std::cout << "minimum is: " << max << std::endl; std::cout << "minimum is: " << min << std::endl; std::cout << "average is: " << ave << std::endl; } int main() { // inputInt(); //Process finished with exit code 143 (interrupted by signal 15: SIGTERM) //since clion is used here, ctrl + c cannot be caught, as a result, // a flag for quit is give at -1. dataLoader(); return 0; }
2.3.2 作业 no.2 (一点点关于友元的介绍)
-
为什么要使用友元?(我目前知道的两个原因)
-
面向对象的思想中很重要得一点就是封装特性,这意味着很多成员不对外暴露权限,这种情况下一些相互协作的工作就会受到阻碍。
-
有些比较反直觉的行为,比如一个object类需要重写一下operator << 操作才可以被自由打印, 但是如果不写成友元实现就会出现一些很不符合直觉的操作如
obj << cout;
-
-
作业要求:
-
这个很简单就是简单运用一下友元实现,实现一个外部函数调用类内似有成员并修改的功能,(电脑以及外部函数升级电脑的cpu)代码见下:
-
Computer.hpp
/* * Created by herryao on 1/15/24. * Email: stevenyao@g.skku.edu * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL) */ #ifndef PROJECT04_COMPUTER_H #define PROJECT04_COMPUTER_H #include<string> #include<iostream> class Computer { private: std::string cpu; public: friend void upgrade(Computer* computer); [[nodiscard]] std::string description() const{ return this->cpu; } Computer(){ this->cpu = "i7"; } }; #endif //PROJECT04_COMPUTER_H
-
main.cpp
#include <iostream> //friend function >> full authority including the private members //encapsulation >> make it safe, but which will result in inconvenience >> access authority //self achievement difficulty, // scenario 1 // "operator << stream function" is declared as a member function, // ( obj << std::cout; ) >> this is not intuitive! // solution: friend // scenario 2 // computer upgrade >> this is not a inner operation, while outside the class there is no access to it. // solution: friend #include "Computer.hpp" void upgrade(Computer* computer){ computer->cpu = "i9"; } int main() { Computer pc; std::cout << pc.description() << std::endl; upgrade(&pc); std::cout << pc.description() << std::endl; return 0; }
-
练习用代码结构如下:
$ tree -L 2
.
├── project01
│ ├── cmake-build-debug
│ ├── CMakeLists.txt
│ └── main.cpp
├── project02
│ ├── Boy.cpp
│ ├── Boy.h
│ ├── clion.log
│ ├── cmake-build-debug
│ ├── CMakeLists.txt
│ ├── Database.cpp
│ ├── Database.h
│ ├── Girl.cpp
│ ├── Girl.h
│ ├── main.cpp
│ ├── Person.cpp
│ └── Person.h
├── project03
│ ├── cmake-build-debug
│ ├── CMakeLists.txt
│ └── main.cpp
└── project04
├── cmake-build-debug
├── CMakeLists.txt
├── Computer.cpp
├── Computer.h
└── main.cpp
8 directories, 19 files
-
心得:
-
回避问题 != 解决问题。
-
强度略大,需要适当调整。
-