强调一下,后面提到的好几个条款都是通过回避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 函数使用可变参数。
因为这些做法有可能导致可移植性的问题。
★不要依赖函数参数的求值顺序(标准未定义)
C++ 标准【没有】明确规定函数参数的求值顺序。因此,如下的代码行为是不确定的。
void Foo(int a, int b); int n = 1; foo(++n, ++n);
★慎用模板特化(不支持新标准)
某些【老式】编译器对“模板偏特化”或“模板全特化”支持不够。
举例:VC6 不支持“模板偏特化”。
★模板继承中,引用基类成员要小心(不支持新标准)
为了直观,给出如下例子:
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); // 会导致二义性错误
下面俺来解释一下:
万一这两个 Foo 函数存在于某个公共函数库中,编译这个库都很正常。但是使用这个库的某个程序调用了 Foo(0); 结果就编译失败了。
★不要依赖标准类型的字长(标准未定义)
某些标准类型(例如 int、wchar_t)的字长会随着具体的平台而改变。
★用枚举代替类的静态成员常量(不支持新标准)
某些【老式】的编译器不支持类的静态成员常量,可以用枚举来代替。
class CFoo { static const int MIN = 0; // 【不】可移植 enum { MAX = 64 }; // 可移植 };
★结尾
今天说了这么一大堆,都比较琐碎,估计会有遗漏的。日后如果大伙儿发现有补充的,欢迎在本帖的评论中指教一二。
由于篇幅有限,和异常相关的内容留到下一个话题来聊。
回到本系列的目录
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者编程随想和本文原始地址:
https://program-think.blogspot.com/2009/01/cxx-cross-platform-develop-2-language.html
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者编程随想和本文原始地址:
https://program-think.blogspot.com/2009/01/cxx-cross-platform-develop-2-language.html
19 条评论
博主,现在的国内大学计算机专业的C/C++教学,竟然推荐学生使用vc6编译器!不知道博主怎么看?
回复删除首先是vc6在win8以上的电脑会有兼容性问题,许多学生第一次安装使用都为此抓狂。
更重要的是,vc6编译器支持的标准早过时了,比如C++头问题加.h的问题。可惜的是书本上老师的ppt上C++范例仍然使用这种语法,结果一些使用gcc编译器的编译不通过搞的一头雾水。
最后最坑爹的是,vc6某些错误的语法竟然能通过编译,一些不标准的语法也没警告。。。
不知道博主怎么看,个人认为学校用于教学使用开源软件再合适不过了。
最起码,教学的东西应该要跟上时代,提供像vc2008这样的也好啊,用vc6这种老古董真的合适吗?
此评论已被作者删除。
删除从学习开发的角度来讲,肯定是不合适的,但是大多数学校只注重 OI,而且教材老套,老师也都是中老年人了,学校是图省事才这么搞的。所以一切都是应试教育的锅。
删除✁ ✂ ✃ ✄ ☎ ✆ ✇ ✈ ✉ ☛ ☞ ✌ ✍ ✎ ✏
回复删除✐ ✑ ✒ ✓ ✔ ✕ ✖ ✗ ✘ ✙ ✚ ✛ ✜ ✝ ✞ ✟
✠ ✡ ✢ ✣ ✤ ✥ ✦ ✧ ★ ✩ ✪ ✫ ✬ ✭ ✮ ✯
✰ ✱ ✲ ✳ ✴ ✵ ✶ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✿
❀ ❁ ❂ ❃ ❄ ❅ ❆ ❇ ❈ ❉ ❊ ❋ ● ❍ ■ ❏
☺ ☻ ♥ ♦ ♣ ♠ • ◘ ○ ❐ ❑ ❒ ▲ ▼ ◆ ❖
◗ ❘ ❙ ❚ ❛ ❜ ❝ ❞
0 1 2 3 4 5 6 7 8 9 A B C D E F
回复删除U+260x ☀ ☁ ☂ ☃ ☄ ★ ☆ ☇ ☈ ☉ ☊ ☋ ☌ ☍ ☎ ☏
U+261x ☐ ☑ ☒ ☓ ☔ ☕ ☖ ☗ ☘ ☙ ☚ ☛ ☜ ☝ ☞ ☟
U+262x ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯
U+263x ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☸ ☹ ☺ ☻ ☼ ☽ ☾ ☿
U+264x ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏
U+265x ♐ ♑ ♒ ♓ ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟
U+266x ♠ ♡ ♢ ♣ ♤ ♥ ♦ ♧ ♨ ♩ ♪ ♫ ♬ ♭ ♮ ♯
U+267x ♰ ♱ ♲ ♳ ♴ ♵ ♶ ♷ ♸ ♹ ♺ ♻ ♼ ♽ ♾ ♿
U+268x ⚀ ⚁ ⚂ ⚃ ⚄ ⚅ ⚆ ⚇ ⚈ ⚉ ⚊ ⚋ ⚌ ⚍ ⚎ ⚏
U+269x ⚐ ⚑ ⚒ ⚓ ⚔ ⚕ ⚖ ⚗ ⚘ ⚙ ⚚ ⚛ ⚜ ⚝ ⚞ ⚟
U+26Ax ⚠ ⚡ ⚢ ⚣ ⚤ ⚥ ⚦ ⚧ ⚨ ⚩ ⚪ ⚫ ⚬ ⚭ ⚮ ⚯
U+26Bx ⚰ ⚱ ⚲ ⚳ ⚴ ⚵ ⚶ ⚷ ⚸ ⚹ ⚺ ⚻ ⚼ ⚽ ⚾ ⚿
U+26Cx ⛀ ⛁ ⛂ ⛃ ⛄ ⛅ ⛆ ⛇ ⛈ ⛉ ⛊ ⛋ ⛌ ⛍ ⛎ ⛏
U+26Dx ⛐ ⛑ ⛒ ⛓ ⛔ ⛕ ⛖ ⛗ ⛘ ⛙ ⛚ ⛛ ⛜ ⛝ ⛞ ⛟
U+26Ex ⛠ ⛡ ⛢ ⛣ ⛤ ⛥ ⛦ ⛧ ⛨ ⛩ ⛪ ⛫ ⛬ ⛭ ⛮ ⛯
U+26Fx ⛰ ⛱ ⛲ ⛳ ⛴ ⛵ ⛶ ⛷ ⛸ ⛹ ⛺ ⛻ ⛼ ⛽ ⛾ ⛿
0 1 2 3 4 5 6 7 8 9 A B C D E F
回复删除U+1F60x �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
U+1F61x �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
U+1F62x �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
U+1F63x �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
U+1F64x �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
��
回复删除��
回复删除😋
回复删除��
回复删除��
删除��
回复删除��
回复删除��
回复删除🐷
回复删除🐷
回复删除🐷
回复删除hello hello yes yes
回复删除This is second test message.
回复删除