在平時的開發中,我們經常會遇到很多和時間有關係的代碼,因此在muduo庫中,作者也設計了Timestamp類,來對時間的使用
頭文件:
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#ifndef MUDUO_BASE_TIMESTAMP_H
#define MUDUO_BASE_TIMESTAMP_H
#include "muduo/base/copyable.h"
#include "muduo/base/Types.h"
#include <boost/operators.hpp>
namespace muduo
{
///
/// Time stamp in UTC, in microseconds resolution.
///
/// This class is immutable.
/// It's recommended to pass it by value, since it's passed in register on x64.
///
class Timestamp : public muduo::copyable,
public boost::equality_comparable<Timestamp>,
public boost::less_than_comparable<Timestamp>
{
public:
///
/// Constucts an invalid Timestamp.
///
Timestamp()
: microSecondsSinceEpoch_(0)
{
}
///
/// Constucts a Timestamp at specific time
///
/// @param microSecondsSinceEpoch
explicit Timestamp(int64_t microSecondsSinceEpochArg)
: microSecondsSinceEpoch_(microSecondsSinceEpochArg)
{
}
void swap(Timestamp& that)
{
std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
}
// default copy/assignment/dtor are Okay
string toString() const;
string toFormattedString(bool showMicroseconds = true) const;
bool valid() const { return microSecondsSinceEpoch_ > 0; }
// for internal usage.
int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; }
time_t secondsSinceEpoch() const
{ return static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); }
///
/// Get time of now.
///
static Timestamp now();
static Timestamp invalid()
{
return Timestamp();
}
static Timestamp fromUnixTime(time_t t)
{
return fromUnixTime(t, 0);
}
static Timestamp fromUnixTime(time_t t, int microseconds)
{
return Timestamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond + microseconds);
}
static const int kMicroSecondsPerSecond = 1000 * 1000;
private:
int64_t microSecondsSinceEpoch_;
};
inline bool operator<(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();
}
inline bool operator==(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch();
}
///
/// Gets time difference of two timestamps, result in seconds.
///
/// @param high, low
/// @return (high-low) in seconds
/// @c double has 52-bit precision, enough for one-microsecond
/// resolution for next 100 years.
inline double timeDifference(Timestamp high, Timestamp low)
{
int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch();
return static_cast<double>(diff) / Timestamp::kMicroSecondsPerSecond;
}
///
/// Add @c seconds to given timestamp.
///
/// @return timestamp+seconds as Timestamp
///
inline Timestamp addTime(Timestamp timestamp, double seconds)
{
int64_t delta = static_cast<int64_t>(seconds * Timestamp::kMicroSecondsPerSecond);
return Timestamp(timestamp.microSecondsSinceEpoch() + delta);
}
} // namespace muduo
#endif // MUDUO_BASE_TIMESTAMP_H
通過頭文件我們能夠學習的知識點:
-
命名空間 namesapce
在c++開發中如果我們需要封裝自己的庫給別人用,一般最後在自己的模塊中加上命名空間,這樣可以防止和比人的模塊因爲重名而導致的衝突 -
Timestamp類繼承了muduo::copyable和 boost::equality_comparable ,boost::less_than_comparable
其實在我們學習c++的過程中有很多的大神和書籍都反覆強調我們在c++中不應該使用多繼承,但是我們卻發現muduo的Timestamp類繼承了三個類,但是當我查看muduo繼承的這三個基類發現:-
muduo::copyable的代碼:
#ifndef MUDUO_BASE_COPYABLE_H #define MUDUO_BASE_COPYABLE_H namespace muduo { /// A tag class emphasises the objects are copyable. /// The empty base class optimization applies. /// Any derived class of copyable should be a value type. class copyable { protected: copyable() = default; ~copyable() = default; }; } // namespace muduo #endif // MUDUO_BASE_COPYABLE_H
通過代碼我們會發現,copyable類什麼也沒有做,子類繼承也沒有任何的用處,查看做的註釋:標籤類強調對象是可複製的。應用空基類優化。任何可複製的派生類都應該是值類型。我們大概明白了這個類其實就是一個空類,表明這個類的是否可以被繼承,如果子類繼承了該類就說明這個類時可以拷貝的,這樣做的好處就是雖然子類繼承了他,但是並不會對子類有任何的影響,,但是使用的人卻可以很直白的知道子類是否可以拷貝。這種類我們把它稱之爲標籤類,通過該類我們可以知道被他繼承的類是不是可以有這樣的操作,Timestamp繼承了copyable,那就說明Timestamp是可以拷貝的。查看muduo庫的代碼,發現類似於copyable的類還有noncopyable。
-
boost::equality_comparable和boost::less_than_comparable
查看boost庫發現這兩個類其實是兩個是用來比較的, 類只要實現對operator==就會自動實現!=
less_than_comparable類 只要實現operator<,可自動實現>、<=、>=,後面有機會再看看這兩個類的實現。
-
-
explicit 關鍵字
explicit Timestamp(int64_t microSecondsSinceEpochArg) : microSecondsSinceEpoch_(microSecondsSinceEpochArg) { }
explicit關鍵字的作用就是防止編譯器進行的隱士構造,從而出現我們預期之外的執行結果。explicit能防止的只是從int64_t到Timestamp的隱式構造 Timestamp t = 12這種事錯誤的,但是Timestamp t(12)正確。
-
成員函數的設計:
通過觀察可以發現Timestamp類有幾個函數並沒有實現爲成員函數,這幾個函數都是需要兩個Timestamp去做一些計算的操作,如果是成員函數,那麼相加和相減這種操作對應的調用改方法的對象的值是會被修改的,但這正不是我們想看到,所以作者把他設計爲普通的函數,返回一個Timestamp對象,這代表着一種編程的思想和原則。需要我們在設計一個類的時候考慮好。
-
const關鍵字的使用
toString、toFormattedString、valid這三個函數是被設計爲const函數,使用了const關鍵字,函數內所有對象成員變量是隻讀,這樣可防止誤改,雖然不加const關鍵字也不一定會錯,但是如果加了const關鍵字就說明該函數是一個讀函數,而不會有寫的操作,這也是一種編程的原則和思想吧,值得學習和借鑑。
-
static成員和函數:
now、invalid、fromUnixTime,這三個函數如果不是static函數那麼我們在使用Timestamp類的時候如果需要獲取一個當前的時間,那麼還得先定義一個Timestamp對象,然後通過對象獲取,這樣就是多此一舉。查看這幾個static函數的實現發現靜態函數是沒有對靜態成員有寫的操作,所以就沒有上鎖的操作,如果有靜態函數的實現有對static成員的寫操作,那麼就會有性能上的下降,這時就應該考慮設計是否合理。kMicroSecondsPerSecond這是一個static變量,該變量是一個在Timestamp中頻繁使用且不會有寫的常量,所以設計爲靜態。
-
成員的命名:
- k開頭的變量說明是一個常量,只是Google的命名規範,可以借鑑
-
static_assert斷言的使用:
static_assert函數是boost提供的一個函數,該函數可以實現在編譯期間斷言的功能,如果在編譯期間static_assert內語句不爲真,那麼就不能編譯通過
總結
通過對muduo庫Timestamp類我們可以學習到知識點有:
- 命名空間 namesapce
- 標籤類的使用
- boost庫中equality_comparable和less_than_comparable類
- explicit關鍵字
- 類涉及到函數的設計
- const成員函數
- static函數和成員的設計
- boost static_assert在編譯期實現斷言
- const變量使用k開頭命名