一、头文件(Timestamp.h)完整注释+语法解析
cpp
// 1. 预处理指令:防止头文件被重复包含(现代编译器支持,替代传统#ifndef/#define/#endif)
// 语法:#pragma是编译器特定预处理指令,once表示该文件仅被包含一次
// 作用:避免多次包含导致的类重复定义编译错误
#pragma once
// 2. 引入C++标准库输入输出流头文件(当前头文件未直接使用,可移除,或保留供后续扩展)
// 语法:#include <头文件名> 引入系统标准头文件,尖括号<>用于系统库
// 作用:提供std::cout、std::endl等输入输出功能
#include <iostream>
// 3. 引入C++标准库字符串类头文件
// 语法:同上,<string>是std::string类的定义所在头文件
// 作用:支持std::string类型的使用(toString()返回值类型)
#include <string>
// 4. 定义Timestamp类(类是C++面向对象的核心,封装数据和行为)
// 语法:class 类名 { 成员声明 }; 类定义以分号结尾
// 作用:抽象时间戳概念,封装时间戳的存储和操作逻辑
class Timestamp
{
// 5. 公有访问控制符(public)
// 语法:public: 后续成员(函数/变量)可被类外部、派生类访问
// 作用:暴露类的对外接口(构造函数、成员函数),供外部调用
public:
// 6. 无参构造函数声明(类内声明,类外定义)
// 语法:类名(); 构造函数无返回值、与类名同名
// 作用:声明一个无参构造函数,用于创建默认时间戳对象(初始化为0)
// 注释补充:默认构造函数若未手动定义,编译器会自动生成,但此处显式声明以明确初始化逻辑
Timestamp();//默认构造函数:创建时间戳对象(默认初始化为 0)
// 7. 带参显式构造函数声明
// 语法:explicit 类名(参数类型 参数名); explicit禁止隐式类型转换
// 作用:声明接收int64_t类型微秒数的构造函数,禁止int64_t隐式转为Timestamp对象
// 符号解析:explicit是C++11关键字,仅修饰单参数构造函数(或无默认值的多参数构造函数)
explicit Timestamp(int64_t microSecondsSinceEpoch);// 显式构造函数:防止隐式转换
// 8. 静态成员函数声明
// 语法:static 返回值类型 函数名(); static修饰类的静态成员函数
// 作用:声明一个无需创建对象即可调用的函数,用于获取当前系统时间戳
// 核心特性:静态函数属于类而非对象,无this指针,不能访问非静态成员变量
static Timestamp now();// 静态成员函数:获取当前时间戳(无需对象)
// 9. 常成员函数声明
// 语法:返回值类型 函数名() const; const修饰成员函数为常成员函数
// 作用:声明将时间戳转为字符串的函数,const保证函数内不修改任何非mutable成员变量
// 核心特性:常对象(const Timestamp ts)只能调用常成员函数
std::string toString() const;// 成员函数:将时间戳转为字符串(const 确保不修改对象)
// 10. 私有访问控制符(private)
// 语法:private: 后续成员仅能被类内部成员函数访问,外部和派生类均不可访问
// 作用:隐藏类的内部数据,保证数据封装性,仅通过公有函数操作数据
private:
// 11. 私有成员变量声明
// 语法:数据类型 变量名_; 下划线结尾是C++工程命名规范,区分参数和成员变量
// 作用:存储自Unix纪元(1970-01-01 00:00:00 UTC)以来的微秒数
// 类型解析:int64_t是C++11固定宽度整数类型(64位有符号整数),定义在<cstdint>,需确保编译环境支持
int64_t microSecondsSinceEpoch_;// 存储自 Unix 纪元的微秒数(1970-01-01 00:00:00 UTC)
};
二、源文件(Timestamp.cpp)完整注释+语法解析
cpp
// 1. 引入C标准库时间头文件
// 语法:#include <time.h> 引入C标准库头文件,提供time()、localtime()、tm结构体等时间相关接口
// 作用:获取系统时间、解析时间戳为年月日时分秒
#include <time.h>
// 2. 引入自定义头文件
// 语法:#include "头文件名.h" 引入项目内自定义头文件,双引号""用于本地文件
// 作用:获取Timestamp类的声明,否则类外定义成员函数会编译报错(编译器不知道类的结构)
#include "Timestamp.h"
// 3. 无参构造函数类外定义
// 语法:类名::类名() : 成员变量(初始化值) { 函数体 }
// 符号解析:
// - :::作用域解析符,明确该构造函数属于Timestamp类(类外定义必须加)
// - ::成员初始化列表起始标记,在构造函数体执行前初始化成员变量(效率高于函数体赋值)
// - ():构造函数参数列表(无参则为空)
// - _:成员变量命名规范,下划线结尾区分参数和成员变量
// 作用:创建Timestamp对象时,将microSecondsSinceEpoch_初始化为0
Timestamp::Timestamp() : microSecondsSinceEpoch_(0)
{
// 4. 空构造函数体
// 语法:{} 包裹函数执行逻辑,此处为空表示无额外操作
// 原因:初始化工作已在成员初始化列表完成,无需函数体赋值
}
// 5. 带参构造函数类外定义
// 语法:类名::类名(参数类型 参数名) : 成员变量(参数值) { 函数体 }
// 符号解析:
// - int64_t:64位有符号整数类型,适配微秒级时间戳的大范围存储
// - microSecondsSinceEpoch:函数参数(小驼峰命名),接收外部传入的微秒数
// - microSecondsSinceEpoch_:类的私有成员变量,存储微秒数
// 作用:根据传入的微秒数初始化Timestamp对象的成员变量
Timestamp::Timestamp(int64_t microSecondsSinceEpoch)
: microSecondsSinceEpoch_(microSecondsSinceEpoch)
{
// 6. 空构造函数体:初始化工作已完成,无额外逻辑
}
// 7. 静态成员函数now()类外定义
// 语法:返回值类型 类名::函数名() { 函数体 }
// 核心规则:静态成员函数类内声明加static,类外定义时不加static
// 符号解析:
// - Timestamp:返回值类型为Timestamp对象
// - :::作用域解析符,定位到Timestamp类
// 作用:获取当前系统时间戳(秒级),转为Timestamp对象并返回
Timestamp Timestamp::now()
{
// 8. 函数体:创建并返回当前时间的Timestamp对象
// 语法解析:
// - time(NULL):C标准库函数,返回time_t类型(本质是long),表示自Unix纪元以来的秒数
// - Timestamp(time(NULL)):调用带参构造函数创建临时Timestamp对象
// - return:返回语句,将临时对象返回(C++会优化临时对象,避免拷贝)
// 注意:因构造函数加了explicit,此处time_t(long)隐式转int64_t后,显式构造对象(无隐式转换,符合explicit设计)
return Timestamp(time(NULL));
}
// 9. 常成员函数toString()类外定义
// 语法:返回值类型 类名::函数名() const { 函数体 }
// 核心规则:const修饰符类内声明和类外定义必须同时保留
// 符号解析:
// - std::string:返回值类型为std命名空间下的string类
// - :::作用域解析符,定位到std命名空间(std::string)和Timestamp类(Timestamp::toString)
// - const:保证函数内不修改任何非mutable成员变量
// 作用:将微秒级时间戳转为"年/月/日 时:分:秒"格式的字符串
std::string Timestamp::toString() const
{
// 10. 定义字符数组缓冲区
// 语法:char 数组名[长度] = {0}; 栈上分配字符数组,{0}初始化所有元素为0
// 符号解析:
// - []:数组长度定义符,128表示数组可存储127个有效字符+1个结束符'\0'
// - = {0}:数组初始化规则,第一个元素设为0,其余自动初始化为0(避免垃圾值)
// 作用:存储格式化后的时间字符串
char buf[128] = {0};
// 11. 将微秒时间戳转为本地时间结构体
// 语法解析:
// - localtime(const time_t* timer):C标准库函数,接收秒级时间戳地址,返回tm结构体指针(本地时区)
// - µSecondsSinceEpoch_:取地址符&,获取成员变量的内存地址
// - tm*:指向tm结构体的指针,*表示指针类型(存储变量地址)
// - 注意(BUG):microSecondsSinceEpoch_是微秒数,需先转为秒数(除以1e6),否则时间解析错误
tm *tm_time = localtime(µSecondsSinceEpoch_);
// 12. 格式化时间字符串到缓冲区
// 语法解析:
// - snprintf(char* buf, size_t size, const char* format, ...):安全格式化函数,避免缓冲区溢出
// - 格式化符号:%4d(4位整数)、%02d(2位整数,不足补0)
// - ->:指针成员访问符,通过tm结构体指针访问成员(如tm_time->tm_year)
// 字段解析:
// - tm_year + 1900:tm_year存储1900年以来的年数,+1900得到实际年份
// - tm_mon + 1:tm_mon存储0-11(0=1月),+1得到实际月份
// - tm_mday:当月日期(1-31)
// - tm_hour:小时(0-23)
// - tm_min:分钟(0-59)
// - tm_sec:秒(0-60,60为闰秒)
snprintf(buf, 128, "%4d/%02d/%02d %02d:%02d:%02d",
tm_time->tm_year + 1900,
tm_time->tm_mon + 1,
tm_time->tm_mday,
tm_time->tm_hour,
tm_time->tm_min,
tm_time->tm_sec);
// 13. 返回格式化后的字符串
// 语法解析:
// - return buf:char[]隐式转为const char*,调用std::string的构造函数(接收const char*),返回string对象
// 作用:将字符数组转为std::string并返回
return buf;
}
三、核心语法&符号总结
| 符号/语法 | 作用 | 出现位置 |
|---|---|---|
#pragma once |
预处理指令,防止头文件重复包含 | 头文件开头 |
#include |
预处理指令,引入头文件(<>系统库/""自定义) |
头文件/源文件开头 |
class |
定义类,封装数据和行为 | 头文件Timestamp类定义 |
public/private |
访问控制符,控制成员的访问权限 | 类内成员分组 |
:: |
作用域解析符,定位类/命名空间的成员 | 类外定义成员函数(Timestamp::)、std::string |
: |
成员初始化列表起始标记,构造函数体执行前初始化成员变量 | 构造函数定义 |
() |
函数参数列表/函数调用/初始化值包裹 | 构造函数、now()、toString() |
{} |
函数体/代码块/数组初始化包裹 | 所有函数体、数组初始化 |
explicit |
禁止构造函数的隐式类型转换 | 带参构造函数声明 |
static |
修饰静态成员函数,属于类而非对象 | now()声明 |
const |
修饰常成员函数,保证不修改成员变量 | toString()声明/定义 |
int64_t |
C++11固定宽度整数类型(64位有符号),适配大范围时间戳存储 | 成员变量、构造函数参数 |
& |
取地址符,获取变量的内存地址 | localtime(µSecondsSinceEpoch_) |
* |
指针类型标记,存储变量地址 | tm* tm_time |
-> |
指针成员访问符,通过指针访问结构体/类成员 | tm_time->tm_year |
[] |
数组长度定义/数组下标访问 | char buf[128] |
return |
函数返回语句,返回指定类型的值/对象 | now()、toString() |
四、关键问题修正(新手必看)
源文件中有2个核心BUG,运行会导致时间显示错误,需修正:
-
微秒转秒(now()函数) :
time(NULL)返回秒数,需转为微秒数(×1000000),否则时间戳单位不匹配:cppTimestamp Timestamp::now() { // 秒转微秒,适配成员变量的微秒单位 int64_t micro_sec = static_cast<int64_t>(time(NULL)) * 1000000; return Timestamp(micro_sec); } -
localtime传入微秒数(toString()函数) :
localtime需要秒数,需将微秒数转为秒数后传入:cpp// 修正:先转秒数,再取地址 int64_t sec = microSecondsSinceEpoch_ / 1000000; tm *tm_time = localtime(reinterpret_cast<const time_t*>(&sec));