您的位置:首页 > 编程语言 > Qt开发

零基础学Qt 4编程实例之四:理解并正确使用名字空间

2010-04-27 22:25 429 查看
我们写一个简单的控制台程序。在用到标准库中的函数时,需要添加对标准库的引用。



按照市面上大多数C++程序设计教科书推荐的做法,可以使用#include <iostream.h>或者是#include “iostream.h”。



我们就启动Qt Creator,在其中建立一个基于控制台的应用程序,代码如下:



#include <QtCore/QCoreApplication>

#include <iostream.h>


int main(int argc, char *argv[])

{


QCoreApplication a(argc, argv);




QString qstr = QObject::tr("Hello Qt!");

string str = qstr.toStdString();

cout << str;



}


接下来依次运行qmake和 Ctrl+B编译程序代码,提示0个错误和2个警告,警告的原话如下:



#warning This file includes at least one deprecated or antiquated header. /

Please consider using one of the 32 headers found in section 17.4.1.2 of the /
C++ standard. Examples include substituting the <X> header for the <X.h> /
header for C++ includes, or <iostream> instead of the deprecated header /
<iostream.h>. To disable this warning use -Wno-deprecated.

其实就是告诉程序员:应该尽量使用#include <iostream>而不是#include <iostream.h>这种形式来包含头文件,前者是C++标准所推荐的做法。

那么我们就本着“消灭任何一个警告”的想法,将程序改为#include <iostream>,修改完成后的代码如下:

#include <QtCore/QCoreApplication>

#include <iostream>

int main(int argc, char *argv[])

{



QCoreApplication a(argc, argv);





QString qstr = QObject::tr("Hello Qt!");

string str = qstr.toStdString();

cout << str;

}


然后Ctrl+B编译程序。



可是,问题又出现了,程序提示一个错误和一个警告,情形如图所示:




图1 编译出现错误

也就是编译器并未识别#include <iostream>这种形式的头文件包含。这里其实涉及到C++中的一个基础知识点:名字空间的使用。
我们借这个问题讲解如下:
iostream是输入/输出流库标准文件(注意它没有后缀),它包含cout的信息,这对我们的程序是必需的。#include是预处理指示符(preprocessor directive),它能使得iostream的内容读入到我们的程序中。

在C++标准库中定义的名字,如cout,不能在程序中直接使用,除非在预处理器指示符:
#include <iostream>
后面加上语句:
using namespace std;

这条语句被称作是using 指示符(using directive)。C++标准库中的名字都是在一个称作std的名字空间中声明的,这些名字在我们的程序文本文件中是不可见的,除非我们显式的使它们可见。using指示符告诉编译器要使用在名字空间std中声明的名字。

这样就清楚了,依据上面的讲解,再次修改代码如下:

#include <QtCore/QCoreApplication>

#include <iostream>

using namespace std;

int main(int argc, char *argv[])

{



QCoreApplication a(argc, argv);


QString qstr = QObject::tr("Hello Qt!");
string str = qstr.toStdString();



cout << str;



}

按下Ctrl+B,编译程序,无错误无警告。程序运行效果如图所示:





图2 程序运行效果



更好的解决方案

为了使名字空间中声明的名字在我们的程序中可见,指示符using通常被视作是一种比较差的选择方案。在上面的程序代码中,指示符using使头文件<string>中声明的、并且位于名字空间std中的所有组件在程序文本文件中都是可见的,这又将全局名字空间污染问题带回来了。而这个问题正是std名字空间首先要努力避免的,它增加了“C++标准库组件的名字”与“我们程序中声明的全局名字”冲突的机会。
现在,我们对命名空间机制已经有了一些了解。有两种机制可以替代指示符using,使得我们可以引用到隐藏在名字空间std中的名字string。

一种是我们可以使用限定的名字,例如:
#include <string>

......



std::string str = qstr.toStdString();


std::cout << str;

或者如下使用using声明:

#include <string>
using std::string;
......




string str = qstr.toStdString();

cout << str;



也就是说,为了使用名字空间中声明的文字,建议使用带有精细选择功能的using声明代替using声明。

顺带多说一句,从技术上来讲,已经没有所谓的<iostream.h>。当标准委员会删除其它non-C标准头文件的扩展名时,就消灭了它。我们可以深入了解一点的是,如果(而且很可能)你的编译器同时支持<iostream>和<iostream.h>,则这两个头文件的包含的意义有所不同。如果你使用#include <iostream>,你取得的是隐藏于namespace std内的iostream程序库的元素;但如果你使用#include <iostream.h>,你却是在global scope中取得那些元素。在global scope中取得的那些元素可能会造成名称冲突,而名字空间正是被设计用来阻止这类问题的发生。除此之外,<iostream>也比<iostream.h>少了2个字,对喜欢追求简洁高效的程序员来说,这个理由或许就足够决定你的选择了。



好了,本节重点就是:理解名字空间的作用并正确的使用它。

扩展阅读:#include <iostream>与#include <iostream.h>的效率问题



使用#include <iostream>与使用#include <iostream.h>在效率上有区别吗?也许有的朋友会问到这个问题,也有一些朋友认为两者不存在效率的差别。那么我试着来解答一下大家的困惑。



首先要明确的是,这两种写法是不同的,这在本节的正文中已经有了说明。



如果是新写程序,那么首选是#include <iostream>,而#include <iostream.h>的写法存在的意义仅仅是为了兼容以前写的C风格的程序。

从功能性的角度来讲,<iostream>包含了一系列模板化的I/O类,相反地<iostream.h>只仅仅是支持字符
流。另外,输入输出流的C++标准规范接口在一些微妙的细节上都已改进,因此,<iostream>和<iostream.h>在接口和执行上都是不同的。最后,<iostream>的各部分组成都是以STL的形式声明的,然而<iostream.h>的各组成都是声明成全局型的。



从上面说的意义上来讲,一般情况下,使用#include <iostream>比使用#include <iostream.h>的程序效率要低一些。


因为这些实质上的不同,你不能在一个程序中混淆使用这两个库。做为一种习惯,在新的代码中一般使用<iostream>,但如果你处理的是过去编写的代码,为了继承,可以用继续用<iostream.h>的方式,以保持代码的一致性。



最后,给出一个具体的例子,大家可以在Qt Creator中构建2个基于控制台的程序,分别运行,测试时间。



程序代码即是main.cpp的完整内容。

第一个,使用名字空间的main.cpp



#include <QtCore/QCoreApplication>






#include <iostream>



using namespace std;



int main(int argc, char *argv[])

{





QCoreApplication a(argc, argv);

QString qstr = QObject::tr("Hello Qt!");
string str = qstr.toStdString();

for ( qint16 i = 0; i < 10000; i++)
{
cout << str +'/n';
}

return a.exec();
}

第二个,不使用名字空间的main.cpp

#include <QtCore/QCoreApplication>

#include <iostream.h>



int main(int argc, char *argv[])

{
QCoreApplication a(argc, argv);

QString qstr = QObject::tr("Hello Qt!");
string str = qstr.toStdString();

for ( qint16 i = 0; i < 10000; i++)
{
cout << str +'/n';
}

return a.exec();
}




在我的机器上测试,前者比后者慢了很多,大概有2-3倍的样子。有兴趣的朋友可以测试一下。



关于名字空间的话题还有很多,就初学C++的朋友而言,这里介绍的已经足够日常使用了。如果有兴趣,可以查阅标准库的说明以及相关著作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: