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

目录

本周每日学习记录

进展

重点内容

练习用代码结构

appendix


本文仅用于记录自己在奇牛软件学习的过程,并对自己起到一个督促性的作用。(目前正在学习C/C++入门的基础语法篇)

作为一名非计算机专业的大龄工科生,我正踏上转向编程(特别是图形学领域)的旅程。在这个过程中,C++成为了我的主要工具。回顾过去一年,我时断时续地学习C++,却发现自己经常在重复相同的概念,没有明确的学习方向,常感到知识点零散且琐碎。

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

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

本周每日学习记录如下:

#Day 01 Thu
2024-01-11 17:57:21: Total study time: 00:10:21
2024-01-11 22:57:21: Total study time: 03:50:21
#Day 02 Fri
2024-01-12 20:52:01: Total study time: 02:43:37
2024-01-12 22:17:46: Total study time: 01:15:15
#Day 03 Sat
2024-01-13 20:09:27: Total study time: 00:36:39
2024-01-13 21:27:45: Total study time: 01:09:28
2024-01-13 22:31:53: Total study time: 01:00:14
2024-01-13 23:58:51: Total study time: 01:26:50
#Day 04 Sun
2024-01-14 18:58:38: Total study time: 00:52:57
2024-01-14 22:11:02: Total study time: 03:00:53
2024-01-14 22:37:37: Total study time: 00:26:19

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

在奇牛软件学院的第一个学习记录_第1张图片

学到的重点内容有:

  • 项目设计思想:问题描述 >> 接口设计 >> 接口实现 >> 成员变量设计

  • sstream(std::std::stringstream)

    • 示例用法:

    •  std::string Car::description() const {
           std::stringstream ret;
           ret << "car brand: " << brand_ << "(" << model_ << ")" << "\n CURRENT MILES: " << miles_
               << "\nPrice: " << getPrice()
               << "\nEngine: " << engine_.description();
           for(int i=0; i<4; ++i){
               ret << "\nTire " << "[" << i  << "]" << tires_[0].description();
           }
           ret << "\n";
           return ret.str();
       }

  • 面向对象编程三大特性封装继承多态:class >>encapsulation>> inheritance >> polymorphism

  • 构造函数constructor,析构函数destructor,拷贝构造函数copy constructor以及拷贝赋值函数copy assignment operator的调用时机和顺序。

  • this 指针

  • Static member类内静态成员的初始化不可以在类内进行,且仅初始化一次。

  • 静态成员函数以及const成员函数的用法。

  • vector中的push_back()方法是一个值拷贝, 这可能会导致设计的偏差。

    • 解决办法,采用指针构造vector

    • #include
       std::vector vec;
       MyClass obj;
       ​
       vec.push_back(&obj); // 添加指向obj的指针
       vec[0]->modify();    // 修改vec中的第一个元素,实际上修改的是obj

  • 建模常用手段:组合composition聚合aggregation

    1. 组合是一种强“拥有”关系。在组合中,部分的生命周期依赖于整体的生命周期。当整体被销毁时,其部分也应该被销毁。

      • 组合通常是通过在包含类中创建另一个类的对象实现的。

      • 例子:考虑一个CarEngine的关系。汽车有一个引擎当汽车被销毁时,其引擎也不再存在。

      •  class Engine {
             // Engine的实现
         };
         ​
         class Car {
         private:
             Engine engine;  // Car包含一个Engine
         public:
             // Car的方法
         };

    2. 聚合是一种弱的“拥有”关系,其中一个类(称为“整体”)包含另一个类(称为“部分”)的对象,但两者的生命周期不一定相关联。换句话说,在聚合关系中,部分可以独立于整体存在。

      • 聚合通常通过在包含类中包含另一个类的对象或者指针来实现。

      • 例子:考虑一个ClassStudent的关系。一个班级包含学生,但学生可以存在于班级之外。

      •  class Student {
             // Student的实现
         };
         ​
         class Class {
         private:
             std::vector students;  // Class包含多个Student
         public:
             void addStudent(const Student& s) {
                 students.push_back(s);
             }
             // Class的其他方法
         };

  • 菱形继承问题diamond inheritance structure >> 继承二异性问题ambiguous error

    • solution: 显式调用或采用虚继承,起始基类被称为虚基类

    • 示例用法:

     #include 
     #include 
     ​
     class Tel{
     public:
         Tel():number_("unknown"){}
     protected:
         std::string number_;
     };
     ​
     //virtual inheritance can be used to solve the diamond inheritance structure
     //the base class named as virtual base class(Tel)
     //solving the problem of ambiguous error
     ​
     //class Fixedline: public Tel{
     class Fixedline: virtual public Tel{
     ​
     };
     ​
     ​
     //class MobilePhone:public Tel{
     class MobilePhone: virtual public Tel{
     ​
     };
     ​
     class Wireless: public Fixedline, public MobilePhone{
     public:
         void setNumber(const std::string& num){
             //ambiguous error
             //in diamond inheritance structure, there will be multi-members inherited,
             // while no way to tell from which
             //explicitly define the member, but too complicated
             //what is the solution?
             //virtual inheritance
             this->number_ = num;
     //        this->Fixedline::number_ = num;
         }
    
         std::string getNumber(){
     //        return this->Fixedline::number_;
             return this->number_;
         }
     };
     ​
     ​
     int main() {
         Wireless w;
         w.setNumber("1000000");
         std::cout << w.getNumber() << std::endl;
         return 0;
     }
     ​
  • 类继承的几种模式public, protected, private

  • 位图算法Bitmap algorithm(空间换速度)

    • 开辟一个足够大小的char型数组初始化为0, 遍历数组存储相应的数据

    • 首先按照8位一组的方式采样数据并访问相应的单元,在单元内采用位运算存储和判断是否存在

    • 具体代码如下所示:

    •  #include 
       #include 
       /*
        * bit map algorithm
        * space -> time
        * 4 billion finding issue
        * */
       ​
       void init(char* data, int len){
           //design following the real problem
           //assuming only (int number % 3 == 0) are stored
           unsigned int n = len*8; //total number of datas
           for (unsigned int i = 0; i < n; ++i){
               //find the number
               if ((i % 3) == 0){
                   //access the pointer -> find the place -> set the value to 1
                   //using the bit binary operator << and |
                   //to be noticed here, the | operator cannot change the value, while |= should be used here
                   *(data + (i/8)) |= (1 << (i % 8 ));
       //            data[i / 8] |= (1 << (i % 8));
               }
           }
       ​
       }
       ​
       bool checkMap(int value, int len, char* dataMap){
           if(((value/8) > len) || (value < 0))
               return false;
           int ind = value/8;
           char temp = 1 << (value%8);
           //using bit and operation to check if the value is activated in the map or not
           return ((dataMap[ind] & temp)!=0);
           //0000 0000
           //0010 0000
       }
       ​
       int main() {
           //assign one enough memory for Bitmap
           //8000000001
           //2147483647 >> signed int
           //4294967295 >> unsigned int
           unsigned int n = 4000000000;
       ​
           // one more promising length < 8, eg: 0, 1, 2, 3, 4, 5, 6
           int len = n / 8 + 1;
           char *data = static_cast (malloc(len));
           //initialize the data at value zero across the Bitmap
           memset(data, 0, len);
           //load the data set(only once)
           init(data, len);
           
           /*=================testing=================*/
           
           while(true){
               std::cout << "please enter the value for searching(-1 for quit): ";
               unsigned int value;
               std::cin >> value;
               if(value == -1)
                   break;
               if(checkMap(value, len, data)){
                   std::cout << "found~" << std::endl;
               }else{
                   std::cout << "no such one value~" << std::endl;
               }
           }
           //always there is one free(delete) operation following the malloc(new)
           free(data);
       ​
       ​
           return 0;
       }
       
       #结果展示
       please enter the value for searching(-1 for quit): 1
       no such one value~
       please enter the value for searching(-1 for quit): 0
       found~
       please enter the value for searching(-1 for quit): 3
       found~
       please enter the value for searching(-1 for quit): 6
       found~
       please enter the value for searching(-1 for quit): 9
       found~
       please enter the value for searching(-1 for quit): 999999
       found~
       please enter the value for searching(-1 for quit): 

    • 潜在问题:以上代码无法处理数据越界的问题,上述代码在数据越界时会导致std::cin的失效,这在极限测试中被发现例如输入数字8000000001,这会造成无限循环(int),或者直接退出(unsigned int)。

    #8000000001
    #2147483647 >> signed int
    #4294967295 >> unsigned int
    #signed int value
    please enter the value for searching(-1 for quit): 8000000001
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    please enter the value for searching(-1 for quit): no such one value~
    ...
    #unsigned int value
    please enter the value for searching(-1 for quit): 8000000001
    
    Process finished with exit code 0
    • 解决方法:在循环末尾对cin进行判断,采用一个来自库中的模板类numeric_limits

    • #include 
      //...other codes...
      //this is for the failure on cin
      if (std::cin.fail()) {
          // clear the error
          std::cin.clear();  
          // solve the error
          std::cin.ignore(std::numeric_limits::max(), '\n'); 
          continue; 
      }

    • 问题解决(值得注意的是unsigned int 直接退出循环了,并没有给cin反映的时间。所以unsigned 类型没有得到纠正)结果如下:

    • please enter the value for searching(-1 for quit): 8000000001
      no such one value~
      please enter the value for searching(-1 for quit): 8000000001
      no such one value~
      please enter the value for searching(-1 for quit): 8000000001
      no such one value~
      please enter the value for searching(-1 for quit): 8000001
      found~
      please enter the value for searching(-1 for quit):

  • 项目数据的永久存储 >> 存储到文件或存储到数据库中

    • c++中的 流对象 输出至 文件 or 控制台 or 特殊数据类型如 stringstream

    • 流对象的继承关系如下图所示:

    • 在奇牛软件学院的第一个学习记录_第2张图片

    • ostream 输出(cout), istream 输入(cin

    • ofstream 文件输出, ifstream文件输入

    • ostringstream字符串输出, istringstream字符串输入

    • iostream {fstream, stringstream} 通用输入输出流

    • 在奇牛软件学院的第一个学习记录_第3张图片

    • std::fsteam 是可读可写的,但是在其使用过程中要注意其默认模式是直接覆盖文件, 使用专业的方法会有利于代码的维护。

    • 写出二进制类型时要注意int类型的强行转换

    //        of << age << "\n";
    of.write((char*)(&age), sizeof(age));
    • 读取二进制时除相应的运用成员方法以外,还应注意 \t space 等无法跳过的问题。

    //still there is problem for type translation, also the `\t` cannot be identified
    //using read() member function to read one more to ignore this character.
    char tmp;
    ifs.read((char*)&tmp, sizeof(tmp));
    // ifs >> age;
    ifs.read((char*)&age, sizeof(age));
    std::cout << age << std::endl;
    • 按照制定格式来写出文本文件(使用中的 stringstream

    std::stringstream s;
    s << "name: " << name << "\t age: " << age << std::endl;
    of << s.str();

    本周练习用代码结构如下:

    $ tree -L 2
    .
    ├── project01
    │   ├── Boy.cpp
    │   ├── Boy.h
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   ├── Girl.cpp
    │   ├── Girl.h
    │   ├── main.cpp
    │   ├── Person.cpp
    │   ├── Person.h
    │   └── readme.md
    ├── project02
    │   ├── Character.cpp
    │   ├── Character.h
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   ├── main.cpp
    │   ├── Toy.cpp
    │   └── Toy.h
    ├── project03
    │   ├── Car.cpp
    │   ├── Car.h
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   ├── Engine.cpp
    │   ├── Engine.h
    │   ├── main.cpp
    │   ├── Tire.cpp
    │   └── Tire.h
    ├── project04
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   └── main.cpp-
    ├── project05
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   └── main.cpp
    ├── project06
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   └── main.cpp
    ├── project07
    │   ├── Book.cpp
    │   ├── Book.h
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   ├── main.cpp
    │   ├── SellBook.cpp
    │   └── SellBook.h
    ├── project08
    │   ├── cmake-build-debug
    │   ├── CMakeLists.txt
    │   ├── main.cpp
    │   ├── ODU330.cpp
    │   ├── ODU330.h
    │   ├── ODU.cpp
    │   └── ODU.h
    └── project09
        ├── biwriting.cpp
        ├── cmake-build-debug
        ├── CMakeLists.txt
        └── main.cpp
    
    18 directories, 44 files

  • 心得:

    • 虽然有过一些学习cpp的经历,但是经过这几天的学习发现自己还是有很多的不足,很多的点扣的不够细致。 目前的知识点单纯凭借代码练习还是可以记住的。

    • 我的计划是在现阶段一些简单的内容倍速快速过一遍,为之后的数据结构算法以及linux系统编程抢出一部分时间。(因为不太敢轻易跳过rock老师的课,毕竟在代码练习里面可能会穿插一些我不了解的知识点)

    • 以后会尽量单日内完成学习总结,并做好文件管理和问题分类,避免特别长的笔记。


appendix

  • 记录由一个shell脚本自动生成,实现计时, 提醒等功能,最终写入至一个log日志中。(借助chatgpt实现)

#!/bin/bash

total_work_time=14400   # 4 hours in seconds
work_period=3600        # 1 hour in seconds
start_time=$(date +"%Y-%m-%d %H:%M:%S")
start_timestamp=$(date +"%s")

trap 'cleanup_and_exit' INT TERM QUIT

cleanup_and_exit() {
    end_time=$(date +"%Y-%m-%d %H:%M:%S")
    end_timestamp=$(date +"%s")
    total_study_time=$((end_timestamp - start_timestamp))
    formatted_total_study_time=$(date -u -d @${total_study_time} +"%H:%M:%S")
    echo "${end_time}: Total study time: ${formatted_total_study_time}" >> ~/qiniu/study.log
    exit
}

while [ $total_work_time -gt 0 ]
do
    seconds_left=$total_work_time
    hours_init=$((seconds_left/3600))
    mins_init=$((seconds_left%3600/60))
    seconds_init=$((seconds_left%60))

    hours_remain=${hours_init}
    mins_remain=${mins_init}
    seconds_remain=${seconds_init}之
    echo "Working time in total is ${hours_init}:${mins_init}:${seconds_init}"
    echo "========================================"

    # Work for 1 hour
    while [ $seconds_left -gt $(($total_work_time - $work_period)) ]
    do
        echo "Keep working for ${hours_remain}:${mins_remain}:${seconds_remain} more......"
        sleep 1s
        seconds_left=$((seconds_left - 1))
        hours_remain=$((seconds_left/3600))
        mins_remain=$((seconds_left%3600/60))
        seconds_remain=$((seconds_left%60))
        clear
        echo "Working time in total is ${hours_init}:${mins_init}:${seconds_init}"
        echo "========================================"
    done

    mplayer -volume 20 ~/Music/rest.mp3  # Play the 'rest' music

    # Prompt user to continue or quit
    while true
    do
        read -p "Type 'continue' to start the next work period or 'q' to quit: " user_input

        if [ "$user_input" == "continue" ]
        then
            break
        elif [ "$user_input" == "q" ]
        then
            cleanup_and_exit
        else
            echo "Invalid input. Please type 'continue' to proceed or 'q' to quit."
        fi
    done

    total_work_time=$((total_work_time - work_period))
done
mplayer -volume 20 ~/Music/done.mp3  # Play the 'done' music upon exit
cleanup_and_exit

你可能感兴趣的:(c++学习,笔记)