在奇牛软件学院的第三个学习记录

本文仅用于记录自己在奇牛软件学习的过程,并对自己起到一个督促性的作用。(目前正在学习C/C++入门的基础语法篇)
作为一名非计算机专业的大龄工科生,我正踏上转向编程(特别是图形学领域)的旅程。在这个过程中,C++成为了我的主要工具。回顾过去一年,我时断时续地学习C++,却发现自己经常在重复相同的概念,没有明确的学习方向,常感到知识点零散且琐碎。

一次偶然的机会,我在B站上看到了Rock老师和学生的交流视频,被他负责任的态度所吸引。在与他简短的沟通后,我决定加入奇牛软件学院。通过学院的项目实践,我希望能够以更系统、实用的方式来掌握C++。同时,我也期待对计算机科学有更深入的理解,尤其是数据结构和算法。

我设定了一个明确的目标:希望在未来一年里,在技能和知识上实现显著的提升。我希望能够将过去零散的学习经历转化为对C++的全面而连贯的理解,为我明年的校园招聘打下坚实的基础。


昨天卡在了一个小点上卡了很久,今天早上找到了一个解决的办法,但是这个问题的原因我并没有理解,还是需要继续探索~~


目录

学习记录

进展

重点内容

代码结构


昨天学习记录如下(今天白天的就不算了)

 #Day 02 Tue
 2024-01-16 20:49:26: Total study time: 04:24:04
 2024-01-16 22:07:59: Total study time: 01:18:22

进展如下(完成视频观看和代码练习,最终代码全部运行成功)

学到的重点内容有:

  1. friend: 友元函数,友元类函数成员,友元类

  2. 运算符重载

    1. 为什么要使用运算符重载?

      使得自定义的类更加符合现实生活中的操作直觉。(一只羊+一只羊 如何表示?一个向量 + 一个向量 表示什么?) >> solution : 运算符重载

    2. 运算符重载的方式:

      类内定义重载, 类外定义重载(friend 友元)

  3. 项目练习:

  • 此次项目是基于之前的相亲平台项目男孩类(Boy)并在其基础上添加各种重载后的运算符,类似课程内,我按照下面顺序逐一进行了实现
 // common operator overloading
 // assignment operator `=` >> binary operator
 // IOSTREAM operator overloading `<<`, `>>`
 // comparison operator `>` `<` >> binary operator
 // [] operator overloading >> unary operator
 //======================================type-conversion=======================================
 //============================================================================================
 // no1. type conversion operator `=`  eg:   Boy boy1 = 10000; // >> constructor: Boy(int);
 //                                      Boy boy2 = "BigBean";// >> constructor: Boy(char*);
 //============================================================================================
 // no2. type conversion operator `=`  eg:   Boy boy("BIGBEAN", 26, 1000, 10);
 //                                      int power = boy;    // >> operator int() overloading
 //                                      char* name = boy;   // >> operator char*() overloading
 // **********************to be noticed, the type conversion operator without a return type~~~~
 //============================================================================================
 // no3. type conversion operator `=`  eg:   Boy boy("BIGBEAN", 26, 1000, 10);
 //                                          Man man = boy;// >> constructor: Boy(char*);
 //============================================================================================
  • 按照老师的课程,我实现了所有的代码的成功运行,并设计了一些dirty的测试代码,解决了一些小bug,但是有些trivial的原理还没理解,正在等待Rock老师的回复。

  • 首先是未修改之前,定义了相关的Boy的一些参数如ID,姓名, 年龄,潜力值,还有一个static的LAST_ID用于存储当前进入人数。

  • 然后是默认的空参构造函数(默认名字为"unknow", 其余所有的相关数值均为 0 ),全参构造函数,以及一个描述函数和一个返回名字的接口

  • 类内的头文件:

     /*
      * 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<cstring>
     ​
     ​
     class Boy{
     public:
         //constructor过
         Boy();
         Boy(const char* name, int age, int salary, int potential);
         //destructor
         ~Boy();
         //member function/ interfaces
         std::string description();
         [[nodiscard]]char* getName()const;
     ​
     private:
         char* name_;
         int age_;
         int salary_;
         int potential_;
         unsigned int id_;
         static int LAST_ID;
     };
     ​
     ​
     #endif //PROJECT01_BOY_H
  • 源文件如下:

    /*
     * Created by herryao on 1/12/24.
     * Email: stevenyao@g.skku.edu
     * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL)
     */
    
    #include "Boy.h"
    
    #include <utility>
    
    //default constructor
    Boy::Boy() {
        this->name_ = nullptr;
        this->potential_ = 0;
        this->age_ = 0;
        this->salary_ = 0;
        this->id_ = ++LAST_ID;
    }
    
    //argument default value defined in the declaration
    Boy::Boy(const char *name, int age, int salary, int potential) {
        if(!name){
            // in cpp-11 directly assignment from a string on a char* variable is not allowed
    //        this->name_ = "unknown";
            this->name_ = new char [sizeof("unknown") +1];
            strcpy(this->name_, "unknown");
        }else{
            //need one end '\0'
            this->name_ = new char[std::strlen(name) +1];
            strcpy(this->name_, name);
        }
    
        this->salary_ = salary;
        this->age_ = age;
        this->potential_ = potential;
        //updating both the information of the boy and also the static member
        this->id_ = ++LAST_ID;
    }
    
    Boy::~Boy() {
        if(this->name_){
            //free the memory
            delete this->name_;
            this->name_ = nullptr;
        }
    }
    
    std::string Boy::description() {
        std::stringstream ret;
        ret << " ID:" << id_ << "Name: " << name_ << " salary: " << salary_ << " potential: " << potential_ << std::endl;
        return ret.str();
    }
    
    char *Boy::getName() const {
        return this->name_;
    }
    
    Boy &Boy::operator=(const Boy &boy) {
        if(this != &boy){
            if(this->name_){
                delete []this->name_;
            }
            //malloc the memory and copy
            this->name_ = new char[std::strlen(boy.getName()) + 1];
            std::strcpy(this->name_, boy.getName());
    
            this->salary_ = boy.salary_;
            this->potential_ = boy.potential_;
            this->age_ = boy.age_;
        }
        return *this;
    }
    
  • 现在开始正式进入代码的练习

  • 注意在main.cpp中,要先初始化定义静态成员变量,我就直接定义在主函数外了(不知道是不是不严谨)

     int Boy::LAST_ID;
     int main() {
         //codes for test;
         return 0;
     }
  • 拷贝赋值操作符号 = 声明为公有

    public:
         Boy& operator=(const Boy& boy);

  • 拷贝赋值的实现

     //copy assignment
     Boy &Boy::operator=(const Boy &boy) {
         if(this != &boy){
             if(this->name_){
                 delete []this->name_;
             }
             //malloc the memory and copy
             this->name_ = new char[std::strlen(boy.getName()) + 1];
             std::strcpy(this->name_, boy.getName());
     ​
             this->salary_ = boy.salary_;
             this->potential_ = boy.potential_;
             this->age_ = boy.age_;
         }
         return *this;
     }

  • 拷贝赋值函数的测试代码

     void test_4_assignment(){
         Boy boy1("BIGBEAN", 30, 3000, 3);
         Boy boy3("MIDIUMBEAN", 20, 2000, 6);
         Boy boy2("SMALLBEAN", 10, 1000, 9);
     ​
     ​
         std::cout << boy1.description() << std::endl;
         std::cout << boy2.description() << std::endl;
         std::cout << boy3.description() << std::endl;
     ​
         std::cout << "after assignment: " << std::endl;
         boy3 = boy2 = boy1;
     ​
         std::cout << boy1.description() << std::endl;
         std::cout << boy2.description() << std::endl;
         std::cout << boy3.description() << std::endl;
     }
     
  • 流操作符号<<, >>: 在这个重载练习中直接涉及到了为什么要使用友元的第一个原因,违反直觉。

  • 如果我们使用类内定义的流运算符重载,默认的第一个输入参数实际上是 this 指针,这会很反直觉,看类内定义的代码:

     public:
         //ostream operator << in-class overloading
         std::ostream& operator << (std::ostream& os) const;
  • 实现:

     //Boy << std::cout //??? how do you think?
     std::ostream &Boy::operator<<(std::ostream &os) const {
         std::stringstream ret;
         ret << "A Boy ID:" << id_ << "Name: " << name_ << " salary: " << salary_ << " potential: " << potential_ << std::endl;
         os << ret.str();
         return os;
     }
  • 为此我设计了一个测试代码,按照我们直觉的写法,他是崩了的

     void test_4_ostream_operator_inclass(){
         Boy boy1("BIGBEAN", 26, 1000, 10);
         std::cout <<"using in-class definition"<< std::endl;
         //it does not work here!
     //    std::cout << boy1 << std::endl;
         //it does work here! but really not intuitive
         boy1 << std::cout << std::endl;
     }
  • 为了解决这一问题,友元定义是必要的,下面把两个流运算符全部实现,类内声明如下,友元可以直接声明为私有:

     private:
         //stream operator overloading using friend
         friend std::ostream& operator<< (std::ostream &os, const Boy& boy);
         //since the object need to be changed const cannot be used here
         friend std::istream& operator>> (std::istream &is, Boy& boy);
  • 源文件的实现,注意这里有一些堆内存的处理,个人认为这个还是应该比较小心的

     //ostream operator <<
     std::ostream &operator<<(std::ostream &os, const Boy &boy) {
         std::stringstream ret;
         ret << "A Boy ID:" << boy.id_ << " Name: " << boy.name_ << " Age: " << boy.age_ << " salary: " << boy.salary_ << " potential: " << boy.potential_ << std::endl;
         os << ret.str();
         return os;
     }
     ​
     //istream operator >>
     std::istream &operator>>(std::istream &is, Boy &boy) {
         std::string name_src;
         char* name = new char[name_src.size() + 1];
         int age, salary, potential;
         std::cout << "please enter the name of boy: ";
         is >> name;
         std::cout << "please enter the age of boy: ";
         is >> age;
         std::cout << "please enter the salary of boy: ";
         is >> salary;
         std::cout << "please enter the potential of boy: ";
         is >> potential;
         boy = Boy{name, age, salary, potential};
         delete[] name;
         //whenever malloc the heap, be sure to free it
     ​
         return is;
     }
  • 下面是测试代码

     //ostream operator <<
     void test_4_ostream_operator_friend(){
         Boy boy1("BIGBEAN", 26, 1000, 10);
         //it does not work here!
         std::cout <<"using friend definition"<< std::endl;
         std::cout << boy1 << std::endl;
         //it does work here! and following the common sense
     }
     ​
     //istream operator >>
     void test_4_istream_operator_friend(){
         Boy boy1;
         std::cout << boy1 << std::endl;
         std::cin >> boy1;
         std::cout <<"after instream operation"<< std::endl;
         std::cout << boy1 << std::endl;
     }
  • 接下来是各种比较运算符操作符号 ==, <, >, 其中包含了一个私有的用于计算分值的govern函数evaluation

     public:
         bool operator >(const Boy& other) const;
         bool operator <(const Boy& other) const;
         bool operator ==(const Boy& other) const;
     private:
         //aiming on evaluation of the comparison operator, one function designed here
         [[nodiscard]]int evaluation() const;
  • 源文件如下:

     //comparison operator overloading
     bool Boy::operator>(const Boy &other) const {
         int score1 = this->evaluation();
         int score2 = other.evaluation();
         return score1 > score2;
     }
     ​
     bool Boy::operator<(const Boy &other) const {
         int score1 = this->evaluation();
         int score2 = other.evaluation();
         return score1 < score2;
     }
     ​
     bool Boy::operator==(const Boy &other) const {
         int score1 = this->evaluation();
         int score2 = other.evaluation();
         return score1 == score2;
     }
     ​
     //govern function
     int Boy::evaluation() const {
         //regulation design
         //salary * potential + (100 - age) * 1000
         return this->salary_ * this->potential_ + (100 - this->age_) * 1000;
     }
  • 测试代码

     void test_4_comparison(){
         Boy boy1("BIGBEAN", 26, 1000, 10);
         Boy boy2("PANGHU", 1, 5, 1);
     ​
         if(boy1 > boy2){
             std::cout << "boy 1 is selected" << std::endl;
         }else if(boy1 == boy2){
             std::cout << "hard to compared" << std::endl;
         }else{
             std::cout << "boy 2 is selected" << std::endl;
         }
     }

  • 以上都还算运行正常,没错然后我就遇到了一些不正常的地方,首先总览一下,接下来我要做的事情是重载一下[]这个操作符号,然后是强转类型的符号

  • 现在开始进行[]操作符号(引发冲突的重载) ,但是在没有重载类型转换符号(int(), char*())之前运行是完全正常的

    public:
    	//operator [] square brackets overloading
    	//the member name_ is a char* type which is hard to be return
    	//only the int type variables are used to overloading the [] operator
    	[[nodiscard]]int operator[](const std::string& id) const;
    	[[nodiscard]]int operator[](const int& id) const;
  • 按照老师说的为了使结果简洁,使用了宏定义以及numerator类型定义,再一次,再未定义类型转换符号重载(int(), char*())之前运行完全正常

    //using macro define
    #define SALARY_KEY "salary"
    #define AGE_KEY "age"
    #define POTENTIAL_KEY "potential"
    #define ID_KEY "id"
    #define SCORE_KEY "score"
    
    //int value is not intuitive, enumerator can be used instead
    typedef enum {
        AGE = 0,
        SALARY,
        POTENTIAL,
        ID,
        SCORE
    }BOY_KEY_TYPE;
  • 测试函数如下,目前为止运行还是正常

    void test_4_squre_brackets(){
        Boy boy1("BIGBEAN", 26, 1000, 10);
        std::cout << "USING STRING INDEX: " << std::endl;
        std::cout << boy1.getName() << " >>> "
                  << "\t salary: " << boy1[SALARY_KEY]
                  << "\t age: " << boy1[AGE_KEY]
                  << "\t potential: " << boy1[POTENTIAL_KEY]
                  << "\t id: " << boy1[ID_KEY]
                  << "\t score: " << boy1[SCORE_KEY]
                  //here since the type conversion is defined aiming on avoiding the ambiguous,
                  // the explicit conversion should be used here
                  << "\n if undefined: " << boy1[std::string("undefine")] << std::endl;
    
        std::cout << "USING ENUMERATOR INDEX: " << std::endl;
        std::cout << boy1.getName() << " >>> "
                  << "\t salary: " << boy1[SALARY]
                  << "\t age: " << boy1[AGE]
                  << "\t potential: " << boy1[POTENTIAL]
                  << "\t id: " << boy1[ID]
                  << "\t score: " << boy1[SCORE]
                  << "\n if undefined: " << boy1[std::string("undefine")] << std::endl;
    }
  • 现在真正的问题来了, 开始定义重载类型转换符号(int(), char*()

    public:
    	//type-conversion using type-conversion operator
    	//to be noticed, the type conversion operator without a return type~~~~
    	operator int () const;
    	operator char* () const;
  • 测试函数

    void test_4_type_conversion_operator(){
        Boy boy("BIGBEAN", 26, 1000, 10);
        int power = boy;
        char* name = boy;
        std::cout << name << ": " << power;
    }
  • 报冲突错误,但是这个错误并不是来自于我的这个类型转换符号的重载,而是来自于之前定义的测试函数,而且,我无法进入debug,直接在编译时候挂掉了,具体报错如下:

    ====================[ Build | project03 | Debug ]===============================
    /home/herryao/Software/clion-2023.2/bin/cmake/linux/x64/bin/cmake --build /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/cmake-build-debug --target project03 -- -j 10
    [ 25%] Building CXX object CMakeFiles/project03.dir/main.cpp.o
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp: In function ‘void test_4_squre_brackets()’:
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:58:57: error: ambiguous overload for ‘operator[]’ (operand types are ‘Boy’ and ‘const char [7]’)
       58 |                                 << "\t salary: " << boy1[SALARY_KEY]
          |                                                         ^
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:58:57: note: candidate: ‘operator[](long int, const char*)’ (built-in)
    In file included from /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:19:
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:62:22: note: candidate: ‘int Boy::operator[](const std::string&) const’
       62 |     [[nodiscard]]int operator[](const std::string& id) const;
          |                      ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:59:54: error: ambiguous overload for ‘operator[]’ (operand types are ‘Boy’ and ‘const char [4]’)
       59 |                                 << "\t age: " << boy1[AGE_KEY]
          |                                                      ^
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:59:54: note: candidate: ‘operator[](long int, const char*)’ (built-in)
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:62:22: note: candidate: ‘int Boy::operator[](const std::string&) const’
       62 |     [[nodiscard]]int operator[](const std::string& id) const;
          |                      ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:60:60: error: ambiguous overload for ‘operator[]’ (operand types are ‘Boy’ and ‘const char [10]’)
       60 |                                 << "\t potential: " << boy1[POTENTIAL_KEY]
          |                                                            ^
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:60:60: note: candidate: ‘operator[](long int, const char*)’ (built-in)
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:62:22: note: candidate: ‘int Boy::operator[](const std::string&) const’
       62 |     [[nodiscard]]int operator[](const std::string& id) const;
          |                      ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:61:53: error: ambiguous overload for ‘operator[]’ (operand types are ‘Boy’ and ‘const char [3]’)
       61 |                                 << "\t id: " << boy1[ID_KEY]
          |                                                     ^
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:61:53: note: candidate: ‘operator[](long int, const char*)’ (built-in)
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:62:22: note: candidate: ‘int Boy::operator[](const std::string&) const’
       62 |     [[nodiscard]]int operator[](const std::string& id) const;
          |                      ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02过/day02/project03/main.cpp:62:56: error: ambiguous overload for ‘operator[]’ (operand types are ‘Boy’ and ‘const char [6]’)
       62 |                                 << "\t score: " << boy1[SCORE_KEY]
          |                                                        ^
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:62:56: note: candidate: ‘operator[](long int, const char*)’ (built-in)
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:62:22: note: candidate: ‘int Boy::operator[](const std::string&) const’
       62 |     [[nodiscard]]int operator[](const std::string& id) const;
          |                      ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp: In function ‘void test_4_type_conversion_operator()’:
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/main.cpp:119:18: error: invalid user-defined conversion from ‘Boy’ to ‘char*’ []8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-fpermissive-fpermissive]8;;]
      119 |     char* name = boy;
          |                  ^~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:55:5: note: candidate is: ‘Boy::operator int() const’ (near match)
       55 |     operator int () const;
          |     ^~~~~~~~
    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day02/project03/Boy.h:55:5: note:   no known conversion from ‘int’ to ‘char*’
    gmake[3]: *** [CMakeFiles/project03.dir/build.make:76: CMakeFiles/project03.dir/main.cpp.o] Error 1
    gmake[2]: *** [CMakeFiles/Makefile2:83: CMakeFiles/project03.dir/all] Error 2
    gmake[1]: *** [CMakeFiles/Makefile2:90: CMakeFiles/project03.dir/rule] Error 2
    gmake: *** [Makefile:124: project03] Error 2
    
  • 然后就是我今天的解决办法,因为我没法进入调试,我直接重写了一边,一个函数一个函数的运行,然后一个测试一个测试的运行,最后发现还是相同位置的冲突,既然如此,问题一定发生在这个函数,这时候我把函数进行了一些修改我把这个函数强行定义成了一个显示转换的函数,其余没变。修改如下:

    public:
    	explicit operator int () const;
    	explicit operator char* () const;
  • 相应地测试函数也必须修改,因为已经不再支持隐式类型转换了:

    void test_4_type_conversion_operator(){
        Boy boy("BIGBEAN", 26, 1000, 10);
    //    int power = boy;
    //    char* name = boy;
        int power = int(boy);
        char* name = static_cast<char*>(boy);
        std::cout << name << ": " << power;
    }
    
    int main() {
    //    test_4_assignment();
    //    test_4_ostream_operator_inclass();
    //    test_4_ostream_operator_friend();
    //    test_4_istream_operator_friend();
    //    test_4_comparison();
    //    test_4_squre_brackets();
    //    test_4_type_conversion_ctor();
        test_4_type_conversion_operator();
        return 0;
    }
    
  • 运行结果如下, 没有报错,但是我认为这不算解决问题,因为那个报错我没看懂,我会继续讨论这个问题:

    /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week02/day03/project01/cmake-build-debug/project01
    BIGBEAN: 84000
    Process finished with exit code 0
  • 然后就是最后一个实现类型之间转换的联系了,说是操作符号重载,其实就是一个新的类中的特殊参数的构造函数而已

  • 我们设计一个类似的类Man, 这个类中人已经不再年轻,于是去掉一个潜力potential的性质吧,Man的设计如下:

     /*
      * Created by herryao on 1/16/24.
      * Email: stevenyao@g.skku.edu
      * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL)
      */
     ​
     #ifndef PROJECT03_MAN_H
     #define PROJECT03_MAN_H
     #include<cstring>
     #include "Boy.h"
     ​
     class Boy;
     ​
     class Man {
     public:
         Man(const char*name, int age, int salary);
         ~Man();
     private:
         char* name_;
         int salary_;
         int age_;
         friend std::ostream & operator << (std::ostream& os, const Man& man);
     };
     ​
     ​
     #endif //PROJECT03_MAN_H
  • Man的实现如下:

     /*
      * Created by herryao on 1/16/24.
      * Email: stevenyao@g.skku.edu
      * Sungkyunkwan Univ. Nano Particle Technology Lab(NPTL)
      */
     ​
     #include "Man.h"
     ​
     Man::Man(const char *name, int age, int salary) {
         if(!name){
             this->name_ = new char[sizeof ("unknown") +1];
             strcpy(this->name_, "unknown");
         }else{
             this->name_ = new char[sizeof (name) +1];
             strcpy(this->name_, name);
         }
         this->age_ = age;
         this->salary_ = salary;
     }
     ​
     Man::~Man() {
         delete []this->name_;
     }
     ​
     std::ostream &operator<<(std::ostream &os, const Man &man) {
         std::stringstream ret;
         ret << "Name: " << man.name_ << " Age: " << man.age_ << " salary: " << man.salary_ << std::endl;
         os << ret.str();
         return os;
     }
     ​

  • 现在开始实现那个类型转换,但是这期间会有类内的一些权限问题,我们不妨直接在Boy类中给Man全权限,记住要引入头文件

  • 还是private的权限吧:

     private:
         friend class Man;
  • 然后在Man的内部实现Boy的构造函数就结束了,下面是声明:

     public:
         Man(const Boy& boy)
  • 源文件的实现,这里面有好多中茴香豆的写法,因为之前重载了很多操作符号,多学学没坏处。

     Man::Man(const Boy &boy) {
         if(!boy.getName()){
             this->name_ = new char[sizeof ("unknown") +1];
             strcpy(this->name_, "unknown");
         }else{
             this->name_ = new char[sizeof (boy.getName()) +1];
             strcpy(this->name_, boy.getName());
             //or the type_conversion to a char* can be also used
     //        this->name_ = new char[strlen((char*)boy) +1];
     //        strcpy(this->name_, (char*)boy);
         }
     //    this->age_ = boy.age_;
     //    this->salary_ = boy.salary_;
         //also the overloading on the square bracket operator can be used
         this->age_ = boy[AGE];
         this->salary_ = boy[SALARY];
     }
  • 最后是测试用代码:

     void test_4_type_conversion_among_classes(){
         Boy boy("BIGBEAN", 26, 1000, 10);
         std::cout << boy;
         Man man = boy;
         std::cout << man;
     }
  • 这个练习就结束了,其实昨天晚上因为上面所说的冲突我回家很晚了,但是还是很不踏实,今天早上回来实验室function by function重新写了一遍(因为我进不去debug,如果有知道这是为什么的可以告诉我下。。。或者写在评论里),但是按照Rock老师说的,这是回避问题不是解决问题,我还得在继续思考下这里面的原因,也就是那个冲突问题。

  • 练习用代码结构如下:

     $ tree -L 2
     .
     ├── project01
     │   ├── cmake-build-debug
     │   ├── CMakeLists.txt
     │   ├── Computer.cpp
     │   ├── Computer.h
     │   ├── ComputerService.cpp
     │   ├── ComputerService.h
     │   └── main.cpp
     ├── project02
     │   ├── Caw.cpp
     │   ├── Caw.h
     │   ├── cmake-build-debug
     │   ├── CMakeLists.txt
     │   ├── Goat.cpp
     │   ├── Goat.h
     │   ├── main.cpp
     │   ├── Pig.cpp
     │   └── Pig.h
     └── project03
         ├── Boy.cpp
         ├── Boy.h
         ├── cmake-build-debug
         ├── CMakeLists.txt
         ├── main.cpp
         ├── Man.cpp
         └── Man.h
     ​
     6 directories, 20 files
     ​
  • 心得:

    • cpp还是很trivial dirty的,很可能一个小点可以卡住很久,你可以直接回避他,但是聪明的人很可能被反噬。

    • 基础并不简单,还是要一遍一遍的过

  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值