`
阿尔萨斯
  • 浏览: 4091379 次
社区版块
存档分类
最新评论

VC++ 6.0的小花招

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>

VC++ 6.0的小花招

许式伟
2006-2-18
Visual Studio系列中产品中,Visual Studio 6.0是最经典的一个版本,虽然后来有Visual Studio .NET 2003,以及2005,也确实添加了很多让我觉得激动的特性,但是从使用细节的细腻程度上来看,VS 6.0无疑是最棒的。我们一些同事甚至试图把2005的C++编译器独立的拿到Visual Studio 6.0中来用,也不愿意升级到.NET上来用,可见其魅力。
和VS 6.0这个产品的成熟相比,VC++ 6.0的编译器的的确确相对来说有些糟糕,其中最被诟病的是对模板技术支持很不好。下面我想做的一件事情,就是向那些继续留恋VC++ 6.0的朋友,介绍一些小花招,来避开VC++ 6.0的一些编译器缺陷。

1)for (type var=expression;;) 中变量var的作用域问题。

按照C++标准,这里定义的变量var出了for循环应该被销毁。也就是说下面这段代码是有效的:
for (int i = 0; i
func();
for (int i = 0; i
func2();
而下面这段代码应该编译不过:
for (int i = 0; i
{
if (has_found_it())
{
handle_find_result();
break;
}
}
if (i == 100)
do_not_found();
然而VC++ 6.0对于第一段代码会报变量i重复定义错误,而第二段代码编译通过。
为了让VC++ 6.0的for语句看起来符合C++标准,你可以这样做:
#define for if (0); else for
你会发现很有趣,这样define一下后,VC++ 6.0的for语句完全符合C++标准了!而且由于编译器的优化,Release版本不会增加任何额外的开销。
喜欢“钻牛角尖”的朋友可能会说:嗯,不错的主意。但是——为什么不这样做:
#define for if (1) for
嗯?看起来也可以。还是让我们看一个用例:
if (cond)
for (int i = 0; i
func1();
else
func2();
进行宏代码展开后,成为:
if (cond)
if (1)
for (int i = 0; i
func1();
else
func2();
这个结果显然不能符合我们的原意。这里func2();语句永远得不到执行机会。

2)模板参数类型如果不出现在参数列表中,则不能作为返回值类型。

由于编译器的缺陷,VC++ 6.0不支持以下这种用法:
template <class t1 class t2></class>
T1 func(T2 arg)
{
T1 var;
... // 处理var过程
return var;
}
void test()
{
int result1 = func<int>(1);</int>
double result2 = func<double>(2);</double>
};
很抱歉,这种用法VC++ 6.0不支持。让人恼火的是,VC++ 6.0编译时不会提示错误,但是生成的执行代码却很成问题。
究其原因,是因为VC++ 6.0的template技术是在编译器的较高层次做的,真正的编译器核心并不考虑模板。以上面的代码为例,对编译器核心来说,只是有两个重载函数而已:
int func(int arg);
double func(int arg);
如果是普通情况,只是返回值不同的函数,是不能同时存在的,编译器应该认为这是一个错误。但是很在模板情况下,这两个函数被简单认为是同一个函数。因为VC++ 6.0会为每个函数根据它的:
1)所在的namespace;
2)所在的类的类名(如果是成员函数);
3)函数名;
4)函数调用方式(cdecl、stdcall还是fastcall);
5)所有参数的类型;
而生成一个唯一标识该函数的函数名。这个过程叫Name Mangling,是所有C++编译器都要进行的工作。而另一个背景是,很多C++编译器生成的目标文件(.obj文件)有一些和模板相关的特殊信息,包括也标识了某个函数是否模板函数。这是因为一个模板函数在多个源文件(.cpp文件)中被调用的话,这个模板函数就会在这些源文件编译生成的目标文件(.obj文件)中都定义(definition)一份。为了支持模板,link程序显然必须知道这个函数是模板函数,从而随意选择一个定义(丢弃其余的定义),而不是报符号重复定义错误。
因为函数名、参数列表等完全一致,所以这两个函数Name Mangling后生成的名字是一样的,并且,它们都被标识为这是模板函数。从而,link程序在工作的时候,简单地将其中一个函数定义给抛弃了。
那么,如果我们非要提供上述的func函数,怎么办?我们来点花招:
template <class t1></class>
class func
{
private:
T1 var;
public:
template <class t2></class>
func(T2 arg)
{
... // 处理var过程
}
operator T1() const
{
return var;
}
};
我们再来使用func这个“函数”:
void test()
{
int result1 = func<int>(1);</int>
double result2 = func<double>(2);</double>
};
呵呵,你会发现,它还真象是你期望的正常工作。

3)仿真VC++提供的关键字__uuidof。

这个技巧不是针对VC++ 6.0缺陷的,而是针对VC++扩展语法的。这个技巧的来由,是为了某些希望有一天有可能要脱离Visual C++环境进行开发的人员。为了脱离VC++,你需要谨慎使用它的所有扩展语法。例如本文讨论的__uuidof。我们先来看看一个例子:
class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Class;
struct __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BB")) Interface;
void test()
{
CLSID clsid = __uuidof(Class);
IID iid = __uuidof(Interface);
...
}
这比起你以前定义uuid的方法简单多了吧?可惜,这样好用的东西,它只在VC++中提供。不过没有关系,我们这里介绍一个技巧,可以让你在几乎所有C++编译器中都可以这样方便的使用__uuidof。这里没有说是所有,是因为我们使用了模板特化技术,可能存在一些比较“古老”的C++编译器,不支持该特性。
也许你已经迫不及待了。好,让我们来看看:
#include <string></string>
#include <cassert></cassert>
inline
STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz)
{
HRESULT hr;
GUID guid;
if (lpsz[0] == '{')
{
hr = CLSIDFromString(lpsz, &guid);
}
else
{
std::basic_string<olechar> strGuid;</olechar>
strGuid.append(1, '{');
strGuid.append(lpsz);
strGuid.append(1, '}');
hr = CLSIDFromString((LPOLESTR)strGuid.c_str(), &guid);
}
assert(hr == S_OK);
return guid;
}
template <class class></class>
struct _UuidTraits {
};
#define _DEFINE_UUID(Class, uuid) /
template /
struct _UuidTraits<class> {/</class>
static const GUID& Guid() {/
static GUID guid = GUIDFromString(L ## uuid); /
return guid;/
}/
}
#define __uuidof(Class) _UuidTraits<class>::Guid()</class>
#define DEFINE_CLSID(Class, guid) /
class Class;/
_DEFINE_UUID(Class, guid)
#define DEFINE_IID(Interface, iid) /
struct Interface;/
_DEFINE_UUID(Interface, iid)
这样一来,就已经模拟出一个__uuidof关键字。我们可以很方便进行uuid的定义。举例如下:
DEFINE_CLSID(Class, "{B372C9F6-1959-4650-960D-73F20CD479BA}");
DEFINE_IID(Interface, "{B372C9F6-1959-4650-960D-73F20CD479BB}");
void test()
{
CLSID clsid = __uuidof(Class);
IID iid = __uuidof(Interface);
...
}
在VC++中,为了与其他编译器以相同的方式来进行uuid的定义,我们不直接使用__declspec(uuid),而是也定义DEFINE_CLSID, DEFINE_IID宏:
#define DEFINE_CLSID(Class, clsid) /
class __declspec(uuid(clsid)) Class
#define DEFINE_IID(Interface, iid) /
struct __declspec(uuid(iid)) Interface
这样一来,我们已经在所有包含VC++在内的支持模板特化技术的编译器中,提供了__uuidof关键字。通过它可以进一步简化你在C++语言中实现COM组件的代价。
附注:关于本文使用的C++模板的特化技术,详细请参阅C++文法方面的书籍,例如《C++ Primer》。其实这个技巧在C++标准库——STL中有一个专门的名字:traits(萃取),你可以在很多介绍STL的书籍中见到相关的介绍。



<!-- Baidu Button BEGIN -->
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "1", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script><!-- Baidu Button END --><!--192.168.100.35--><!-- Baidu Button BEGIN --><script type="text/javascript" id="bdshare_js" data="type=tools&amp;uid=1536434"></script><script type="text/javascript" id="bdshell_js"></script><script type="text/javascript"> document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000) </script><!-- Baidu Button END -->
主题推荐
vc++ visual c++ namespace 技术 标准
猜你在找
<script type="text/javascript"> var searchtitletags = ' VC++ 6.0的小花招' + ',' + 'vc++,visual c++,namespace,技术,标准'; searchService({ index: 'blog', query: searchtitletags, from: 10, size: 10, appendTo: '#res-relatived', url: 'recommend', his: 2, client: "blog_cf_enhance", tmpl: '<dd style="background:url(http://static.blog.csdn.net/skin/default/images/blog-dot-red3.gif) no-repeat 0 10px;"><a href="#{ url }" title="#{ title }" strategy="#{ strategy }">#{ title }</a></dd>' }); </script>
<script type="text/javascript"> new Ad(4, 'ad_cen'); </script>
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
<script type="text/javascript"> var fileName = '2239178'; var commentscount = 0; var islock = false </script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/comment.js"></script>
<script type="text/javascript"> new Ad(5, 'ad_bot'); </script>
<script type="text/javascript"> $(function () { $("#ad_frm_0").height("90px"); setTimeout(function(){ $("#ad_frm_2").height("200px"); },1000); if($("#comment_content").length>0) { $("#quick-reply").show(); $("#quick-reply").click(function(){ setEditorFocus(); }); } var d_top = $('#d-top-a'); document.onscroll = function () { var scrTop = (document.body.scrollTop || document.documentElement.scrollTop); if (scrTop > 500) { d_top.show(); } else { d_top.hide(); } } $('#d-top-a').click(function () { scrollTo(0, 0); this.blur(); return false; }); }); </script><style type="text/css"> .tag_list { background: none repeat scroll 0 0 #FFFFFF; border: 1px solid #D7CBC1; color: #000000; font-size: 12px; line-height: 20px; list-style: none outside none; margin: 10px 2% 0 1%; padding: 1px; } .tag_list h5 { background: none repeat scroll 0 0 #E0DBD3; color: #47381C; font-size: 12px; height: 24px; line-height: 24px; padding: 0 5px; margin: 0; } .tag_list h5 a { color: #47381C; } .classify { margin: 10px 0; padding: 4px 12px 8px; } .classify a { margin-right: 20px; white-space: nowrap; } </style>
    个人资料
    • 访问:1381121次
    • 积分:83466分
    • 排名:第4名
    • 原创:7468篇
    • 转载:0篇
    • 译文:0篇
    • 评论:81条
    文章搜索
    <script type="text/javascript"> $(function () { $("#btnSubmit").click(function () { search(); }); $("#frmSearch").submit(function () { search(); return false; }); function search() { var url = "http://so.csdn.net/so/search/s.do?q=" + encodeURIComponent($("#inputSearch").val()) + "&u=" + username + "&t=blog"; window.location.href = url; } }); </script>
      文章存档
      推荐文章
      <script type="text/javascript"> new Ad(12, 'ad_commend'); </script>
        最新评论
      <script type="text/javascript" src="http://csdnimg.cn/rabbit/cnick/cnick.js"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/newblog.min.js"></script><script type="text/javascript" src="http://medal.blog.csdn.net/showblogmedal.ashx?blogid=254649"></script><script type="text/javascript"> document.write('<script type="text/javascript" src="http://csdnimg.cn/pubfooter/js/publib_footer.js?' + Math.floor(new Date() / 120000).toString(36) + '="></' + 'script>'); </script><script type="text/javascript" src="http://passport.csdn.net/content/loginbox/login.js"></script><script type="text/javascript">document.write("<img src=http://counter.csdn.net/pv.aspx?id=24 border=0 width=0 height=0>");</script><script type="text/javascript" src="http://www.csdn.net/ui/scripts/Csdn/counter.js"></script><script type="text/javascript" src="http://ad.csdn.net/scripts/ad-blog.js"></script><script type="text/javascript" src="http://zz.csdn.net/js/count.js"></script><script type="text/javascript"> $(function () { function __get_code_toolbar(snippet_id) { return $("<a href='https://code.csdn.net/snippets/" + snippet_id + "' target='_blank' title='在CODE上查看代码片' style='text-indent:0;'><img src='https://code.csdn.net/assets/CODE_ico.png' width=12 height=12 alt='在CODE上查看代码片' style='position:relative;top:1px;left:2px;'/></a>" + "<a href='https://code.csdn.net/snippets/" + snippet_id + "/fork' target='_blank' title='派生到我的代码片' style='text-indent:0;'><img src='https://code.csdn.net/assets/ico_fork.svg' width=12 height=12 alt='派生到我的代码片' style='position:relative;top:2px;left:2px;'/></a>"); } $("[code_snippet_id]").each(function () { __s_id = $(this).attr("code_snippet_id"); if (__s_id != null && __s_id != "" && __s_id != 0 && parseInt(__s_id) > 70020) { __code_tool = __get_code_toolbar(__s_id); $(this).prev().find(".tools").append(__code_tool); } }); }); </script>
      分享到:
      评论

      相关推荐

      Global site tag (gtag.js) - Google Analytics