快速业务通道

C++的可移植性和跨平台开发[2]:语法

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29

目前还有相当一部分开发人员在使用老式编译器干活,这些老式编译器可能对C++98支持 不够。因此,当你的代码移植到这些老式的编译器上时,可能会碰到一些稀奇古怪的问题( 包括编译出错和运行时错误)。下面这些注意事项有助于你绕过这些问题。

强调一下 ,后面提到的好几个条款都是通过回避C++的新语法来保证移植性。如果你用的是新式编译器 ,那么你可以不理会这些条款。

★小心for循环变量的作用域(不支持新标准)

在C++98标准中,for循环变量的作用域局限在循环体内。而某些老的编译器(例如 Visual C++ 6)认为for循环变量的作用域在循环体外。所以如下的代码可能导致移植问题。

{
 for(int i=0; i<XX; i++)
 {
  // ...
 }
 for(int i=0; i<XXX; i++)
 {
  // ...
 }
}

建议修改为不同的循环变量,如下所示:

{
 for (int i=0; i<XX; i++)
 {
  // ...
 }
 for(int  j=0; j<XXX; j++)
 {
  // ...
 }
}

★不 要使用全局类对象,改用单键(标准未定义)

全局类对象的构造函数先于main()函数 执行,如果某个模块中同时包含若干个全局类对象,则它们的构造函数的调用顺序是不确定 的。而单键是在第一次调用时被初始化,能避免此问题。另外,单键虽然解决了构造问题, 但是析构依然有隐患。详见“C++ 对象是怎么死的?进程篇”。

★保持 inline函数尽量简单

不要在inline函数内部使用局部静态变量,不要在inline函数使 用可变参数。这些都有可能导致移植问题。

★不要依赖函数参数的求值顺序(标准未 定义)

标准没有明确规定函数参数的求值顺序。因此,如下的代码行为是不确定的。

void Foo(int a, int b);
int n = 1;
foo(++n,  ++n);

★慎用模板特化(不支持新标准)

有些老式编译器对偏特化或 全特化支持不够。

★模板继承中,引用基类成员要小心(不支持新标准)

看 如下例子:

template <typename T>
class TBase
{
protected:
 typedef std::vector<T> Container;
 Container  m_container;
};
template <typename T>
class TDerived :  public TBase<T>
{
 typedef TBase<T> BaseClass;
public:
 void Func()
 {
  typename BaseClass::Container  foo;  //可移植
  Container foo; //不可移植
  this- >m_container.clear(); //可移植
  m_container.clear(); //不可移植
 }
};

★慎用RTTI(不支持新标准、标准未定义)

先声明一 下,我这里说的RTTI主要是指typeid操作符和type_info类型。

首先,由于某些老式 编译器可能不支持typeid操作符和type_info类型,会导致移植性的问题,这是慎用RTTI的一 个原因。(如果你用的是新式编译器,不用考虑这个因素)

其次,由于标准对于 type_info类型的约束比较简单。这导致了不同的编译器对type_info的实现有较大差异。如 果你确实要使用type_info类型,建议仅仅使用它的operator==和operator!=这两个成员函数 。

所以,如果你确实需要在运行时确定类型,又不想碰到上述问题,可以考虑在自己 的类体系中加入类型信息来实现。比如MFC和wxWidgets都是这么干的。

★慎用嵌套类 (不支持新标准)

如果在内部类访问外部类的非公有成员,要把内部类声明为外部类 的friend。

如下代码存在移植问题。

class COuter
{
private:
 char* m_name;
public:
 class CInner
 {
  void Print(COuter* outer)
  {
   cout << outer- >m_name;
  }
 };
};

应该改为如下代码

class COuter
{
private:
 char* m_name;
public:
 class CInner; //前置声明
 friend class CInner;
  class CInner
 {
  void Print(COuter* outer)
  {
    cout << outer->m_name;
  }
 };
};

★ 不要定义参数类型相近的函数(标准未定义)

void Foo(short n);
void Foo(long n);
Foo(0); //会导致二义性错误

★不要依赖标 准类型的字长(标准未定义)

某些标准类型(例如int、wchar_t)的字长会随着具体 的平台而改变。

★用枚举代替类的静态成员常量(不支持新标准)

某些老式 的编译器不支持类的静态成员常量,可以用枚举来代替。

class CFoo
{
 static const int MIN = 0; //不可移植
 enum { MAX = 64  }; //可移植
};

今天说了这么一大堆,都比较琐碎,估计会有遗漏 的。日后如果大伙儿发现有补充的,欢迎在本帖的评论中指教一二。由于篇幅有限,我把和 异常相关的内容留到下一个话题。

原始地址:http://program- think.blogspot.com/

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号