目录
作为一名非计算机专业的大龄工科生,我正踏上转向编程(特别是图形学领域)的旅程。在这个过程中,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
项目设计思想:问题描述
>> 接口设计
>> 接口实现
>> 成员变量设计
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<vector>
?std::vector<MyClass*> vec;
?MyClass obj;
??
?vec.push_back(&obj); // 添加指向obj的指针
?vec[0]->modify(); ? ?// 修改vec中的第一个元素,实际上修改的是obj
建模常用手段:组合composition
和聚合aggregation
组合是一种强“拥有”关系。在组合中,部分的生命周期依赖于整体的生命周期。当整体被销毁时,其部分也应该被销毁。
组合通常是通过在包含类中创建另一个类的对象实现的。
例子:考虑一个Car
和Engine
的关系。汽车有一个引擎当汽车被销毁时,其引擎也不再存在。
?class Engine {
? ? ?// Engine的实现
?};
??
?class Car {
?private:
? ? ?Engine engine; ?// Car包含一个Engine
?public:
? ? ?// Car的方法
?};
聚合是一种弱的“拥有”关系,其中一个类(称为“整体”)包含另一个类(称为“部分”)的对象,但两者的生命周期不一定相关联。换句话说,在聚合关系中,部分可以独立于整体存在。
聚合通常通过在包含类中包含另一个类的对象或者指针来实现。
例子:考虑一个Class
和Student
的关系。一个班级包含学生,但学生可以存在于班级之外。
?class Student {
? ? ?// Student的实现
?};
??
?class Class {
?private:
? ? ?std::vector<Student> students; ?// Class包含多个Student
?public:
? ? ?void addStudent(const Student& s) {
? ? ? ? ?students.push_back(s);
? ? }
? ? ?// Class的其他方法
?};
菱形继承问题diamond inheritance structure
>> 继承二异性问题ambiguous error
solution: 显式调用或采用虚继承,起始基类被称为虚基类
示例用法:
?#include <iostream>
?#include <string>
??
?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 <iostream>
?#include <cstring>
?/*
? * 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<char*> (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进行判断,采用一个来自<limits>
库中的模板类numeric_limits
#include <limits>
//...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<std::streamsize>::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
流对象的继承关系如下图所示:
ostream
输出(cout
), istream
输入(cin
)
ofstream
文件输出, ifstream
文件输入
ostringstream
字符串输出, istringstream
字符串输入
iostream
{fstream
, stringstream
} 通用输入输出流
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;
按照制定格式来写出文本文件(使用<sstream>
中的 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老师的课,毕竟在代码练习里面可能会穿插一些我不了解的知识点)
以后会尽量单日内完成学习总结,并做好文件管理和问题分类,避免特别长的笔记。
记录由一个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