打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
qDebug 学习小结

在qtcentre中看到有网友问这样一个问题:

Why this doesn't work? qDebug() << "Test" << std::endl;
  • 第一反应:这两个东西本来就不能这样搭配使用啊。
  • 第二反应:额,如何解释这个问题呢?还真不知道
  • 第三反应:...

std::cout<<std::endl;

在Qt中用了二三年C++了,还真没想过C++中的这么一个简单的语句是怎么工作的:

  • 只知道std::endl等价于换行+flush
  • 再一想,却不知道endl是什么东西了

函数指针

std::endl 是一个模板函数的函数指针

template <class charT, class traits>  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );

看看GCC中的具体实现

template<typename _CharT, typename _Traits>    inline basic_ostream<_CharT, _Traits>&     endl(basic_ostream<_CharT, _Traits>& __os)    { return flush(__os.put(__os.widen('/n'))); }

操作符重载

<<   原本是移位操作符,毫无疑问这儿是重载以后的:

typedef basic_ostream<_CharT, _Traits> __ostream_type;      __ostream_type&operator<<(__ostream_type& (*__pf)(__ostream_type&)){    return __pf(*this);}

这样以来我们就是它是怎么工作的了。也知道下面两个也就等价了

std::cout<<std::endl;std::endl(std::cout);

带参数的操纵符?

std::endl、std::flush、std::hex等等都称为 Manipulator。如前所述,他们都是函数指针。

除此之外,还有一些带参数的 Manipulator,比如:

std::cout<<std::setw(8);

这又是神马东西(反正不像是函数指针了)?

  • 看看GCC的头文件:
inline _Setwsetw(int __n){ return { __n }; }
  • 函数返回值是一个结构体_Setw 的对象

struct _Setw { int _M_n; };
  • 同样需要操作符<< 重载

template<typename _CharT, typename _Traits>inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, _Setw __f){  __os.width(__f._M_n);  return __os; }

qDebug

  • 首先qDebug有两个重载的函数:
void qDebug(const char *, ...);QDebug qDebug();
  • 后者需要包含QDebug这个头文件才能使用,大家都比较熟悉了。
  • 其次,如果定义了宏  QT_NO_DEBUG_OUTPUT ,qDebug将什么都不做。这是因为:

#ifdef QT_NO_DEBUG_OUTPUT#  define qDebug while(false)qDebug#endif

qInstallMsgHandler()

qInstallMsgHandler 设置的是一个静态的函数指针变量(handler):

typedef void (*QtMsgHandler)(QtMsgType, const char *);static QtMsgHandler handler = 0;QtMsgHandler qInstallMsgHandler(QtMsgHandler h){    QtMsgHandler old = handler;    handler = h;#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB)    if (!handler && usingWinMain)        handler = qWinMsgHandler;#endif    return old;}

qDebug 和这个东西是怎么联系上的?

  • 首先,参数可变的 qDebug 调用了 qt_message 函数:
void qDebug(const char *msg, ...){    va_list ap;    va_start(ap, msg); // use variable arg list    qt_message(QtDebugMsg, msg, ap);    va_end(ap);}
  • 然后借助QString做个转换,调用qt_message_output函数:
static void qt_message(QtMsgType msgType, const char *msg, va_list ap){    QByteArray buf;    if (msg)        buf = QString().vsprintf(msg, ap).toLocal8Bit();    qt_message_output(msgType, buf.constData());}
  • 在这个函数中
    • 如果安装有MsgHandler(即静态的函数指针变量handler非0),则使用

    • 如果未安装,则输出到标准出错(注意:qDebug之所以换行是这儿引入的!)
void qt_message_output(QtMsgType msgType, const char *buf){    if (handler) {        (*handler)(msgType, buf);    } else {        fprintf(stderr, "%s/n", buf);        fflush(stderr);    }...

QDebug

我们似乎很少 (fix me)直接使用这个类,一般都是通过qDebug()生成一个对象来使用

QDebug qDebug() { return QDebug(QtDebugMsg); }

有意思的一点:这样使用时,只有当QDebug析构时,才会将内容输出(看到前面提到的qt_message_output了吧?):

inline ~QDebug() {    if (!--stream->ref) {        if(stream->message_output) {            qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());        }        delete stream;    }}

流操作符

同一开始提到的C++标准库中的流操作符一样,在这儿我们也可以使用不带参数的和带参数的流操作符(注意endl和std::endl的区别):

qDebug()<<qSetFieldWidth(8)<<800<<endl;
  • 首先,肯定有相应的重载操作符:
class QDebug{...    inline QDebug &operator<<(QTextStreamFunction f) {        stream->ts << f;        return *this;    }    inline QDebug &operator<<(QTextStreamManipulator m)    { stream->ts << m; return *this; }
  • 然后有相应的函数指针类型 和 类类型
typedef QTextStream & (*QTextStreamFunction)(QTextStream &);class QTextStreamManipulator{...};

QDebug::space()等

QDebug的三个成员函数看Manual总觉得晕乎乎的,看代码就很直观了

class QDebug{...    inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }    inline QDebug &nospace() { stream->space = false; return *this; }    inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }

参考

  • The C++ Standard Library: A Tutorial and Reference
  • http://www.cppblog.com/yindf/archive/2009/05/12/80382.html

  • Qt Manual 及 源码

 


原文链接:http://blog.csdn.net/dbzhang800/article/details/6460229
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C++ Primer Plus 十三章 类的继承 DMA程序 源代码及附注 vs2012通过
VC6.0中重载操作符函数无法访问类的私有成员
C++运算符重载(2)
为IOStream平反
在c中重载流提取操作符
C++ endl 详解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服