在平时的开发中,我们经常会遇到很多和时间有关系的代码,因此在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类我们可以学习到知识点有:

  1. 命名空间 namesapce
  2. 标签类的使用
  3. boost库中equality_comparable和less_than_comparable类
  4. explicit关键字
  5. 类涉及到函数的设计
  6. const成员函数
  7. static函数和成员的设计
  8. boost static_assert在编译期实现断言
  9. const变量使用k开头命名