| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6322 人关注过本帖
标题:推荐:C++语言常见问题解答
取消只看楼主 加入收藏
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样从 C++ 中呼叫 C 的函数 "f(int,char,float)"? 
 
告诉 C++ 编译器说:它是个 C 的函数: 
         extern "C" void f(int,char,float); 
 
确定你有 include 进来完整的函数原型 (function prototype)。一堆 C 的函数可 
以用大括号框起来,如下: 
 
         extern "C" { 
           void* malloc(size_t); 
           char* strcpy(char* dest, const char* src); 
           int   printf(const char* fmt, ...); 
         } 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样才能建一个 C++ 函数 "f(int,char,float)",又能被 C 呼叫? 
 
想让 C++ 编译器知道 "f(int,char,float)" 会被 C 编译器用到的话,就要用到前 
一则 FAQ 已详述的 "extern C" 语法。接著在 C++ 模组内定义该函数: 
 
         void f(int x, char y, float z) 
         { 
           //... 
         } 
 
"extern C" 一行会告诉编译器:送到 linker 的外部资讯要采用 C 的呼叫惯例及签 
名编码法(譬如,前置一个底线)。既然 C 没有多载名称的能力,你就不能让 C 程 
式能同时呼叫得到多载的函数群。 
 
警告以及实作相关事项: 
  * 你的 "main()" 应该用 C++ 编译之(为了静态物件的初始化)。 
  * 你的 C++ 编译器应该能设定连结的程序(为某些特殊的程式库)。 
  * 你的 C 和 C++ 编译器可能要是同一个牌子的,而且是相容的版本(亦即:有相 
    同的呼叫惯例等等)。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
为什麽 linker 有这种错误讯息:C/C++ 函数被 C/C++ 函数呼叫到? 
 
看前两则 FAQs 关於 extern "C" 的使用。 
 
======================================== 
 
Q108:该怎麽把 C++ 类别的物件传给/传自 C 的函数? 
 
例子: 
 
         /****** C/C++ header file: Fred.h ******/ 
         #ifdef __cplusplus    /*"__cplusplus" is #defined if/only-if 
                                  compiler is C++*/ 
           extern "C" { 
         #endif 
 
         #ifdef __STDC__ 
           extern void c_fn(struct Fred*);       /* ANSI-C prototypes */ 
           extern struct Fred* cplusplus_callback_fn(struct Fred*); 
         #else 
           extern void c_fn();                   /* K&R style */ 
           extern struct Fred* cplusplus_callback_fn(); 
         #endif 
 
         #ifdef __cplusplus 
           } 
         #endif 
 
         #ifdef __cplusplus 
           class Fred { 
           public: 
             Fred(); 
             void wilma(int); 
           private: 
             int a_; 
           }; 
         #endif 
 
"Fred.C" 是个 C++ 模组: 
 
         #include "Fred.h" 
         Fred::Fred() : a_(0) { } 
         void Fred::wilma(int a) : a_(a) { } 
 
         Fred* cplusplus_callback_fn(Fred* fred) 
         { 
           fred->wilma(123); 
           return fred; 
         } 
 
"main.C" 是个 C++ 模组: 
 
         #include "Fred.h" 
 
         int main() 
         { 
           Fred fred; 
           c_fn(&fred); 
           return 0; 
         } 
 
"c-fn.c" 是个 C 模组: 
 
         #include "Fred.h" 
         void c_fn(struct Fred* fred) 
         { 
           cplusplus_callback_fn(fred); 
         } 
 
把指向 C++ 物件的指标传到/传自 C 的函数,如果传出与收回的指标不是“完全相 
同”的话,就会失败。譬如,不要传出一个基底类别的指标却收回一个衍生类别的指 
标,因为 C 编译器不懂该怎麽对多重及虚拟继承的指标做转型。

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
C 的函数能不能存取 C++ 类别的物件资料? 
 
有时可以。 
 
(请先读一读前一则关於和 C 函数间传递 C++ 物件的 FAQ。) 
 
你可以安全地从 C 函数中存取 C++ 物件的资料,只要 C++ 的物件类别: 
  * 没有虚拟函数(包含继承下来的虚拟函数). 
  * 所有资料都在同一个存取等级中 (private/protected/public). 
  * 完全被包含的子物件中也都没有虚拟函数. 
 
如果 C++ 类别有任何基底类别(或是任何被完全包含的子物件中有基底类别)的话 
,技术上来说,存取该资料没有可携性的,因为语言没规定在继承之下的类别配置是 
什麽样子。不过经验上,所有 C++ 编译器的做法都一样:基底类别物件先出现(在 
多重继承之下,则由左到右排列之),子物件次之。 
 
还有,如果类别(或是任何基底类别)含有任何虚拟函数,你时常可以(但不是一直 
都可以)假设有一个 "void*" 出现在物件第一个虚拟函数之所在,或是在该物件的 
第一个 word 那里。同样的,语言对它也没规定到,但这似乎是「大家」都采取的做 
法。 
 
如果该类别有任何虚拟基底类别,情况会更复杂而且更没有可携性。常见的做法是: 
让物件最後才包含基底类别之物件 (V)(不管 "V" 在继承阶层中在哪儿出现),物 
件的其他部份则以正常的次序出现。每个有 V 这个虚拟基底类别的衍生类别,实际 
上都有个“指标”指向最後一个物件的 V 的部份。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
为什麽我总觉得 C++ 让我「离机器更远了」,不像 C 那样? 
 
因为事实上正是如此。 
 
做为一个 OOPL,C++ 让你以该问题的领域来思考,让你以问题领域的语言来设计程 
式,而非以解题的领域来著手。 
 
一个 C 最强的地方是:它没有「隐藏的机制」:你看到的就是你得到的,你可以一 
边阅读 C 的程式,一边「看到」每个系统时脉。C++ 则不然; C 的老手(像从前的 
我们)对这种特性常会有矛盾的心理(或是说「敌视」),但是很快的他们会发现: 
C++ 提供了抽象化的层次及经济的表现能力,大大降低维护成本,又不会损及执行效 
率。 
 
很自然的,用任何语言都会写出坏程式;C++ 并不会确保任何高品质、可重用性、抽 
象化,或是任何「正字标记」的品质因子。C++ 不会让差劲的程式者写不出差劲的程 
式;她只是协助明智的发展者做出高人一等的软体。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
「指向成员函数的指标」和「指到函数的指标」的型态有差别吗? 
 
是的。 
 
考虑底下的函数: 
 
         int f(char a, float b); 
 
如果它是普通的函数,它的型态是:            int (*)      (char,float); 
如果它是 Fred 类别的运作行为,它的型态是:  int (Fred::*)(char,float); 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:50
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样把指向成员函数的指标传给 signal handler、X event callback 等等? 
 
【译注】这是和 UNIX、X Window System 相关的问题,但其他系统亦可推而广之。 
 
不要这样做。 
 
因为若无物件去启动它,成员函数是无意义的,你不能直接使用它(如果 X 视窗系 
统是用 C++ 写的话,或许就可以直接传物件的参考值了,而不光是传个指向函数的 
指标;自然地,物件会包含所有要用到的函数,甚至更多)。 
 
若想修改现有的软体,可拿最顶层的(非成员的)函数当作一层包装 (wrapper),透 
过其他技巧(或许是放在全域变数中),把该物件包起来。这个最顶层的函数,会透 
过适当的成员函数去使用该全域变数。 
 
譬如,你想在中断处理中呼叫 Fred::memfn() 的话: 
 
         class Fred { 
         public: 
           void memfn(); 
           static void staticmemfn();    // 用个 static 成员函数就行了 
           //... 
         }; 
 
         //wrapper 函数会记得哪个物件该去启动全域物件的成员函数: 
         Fred* object_which_will_handle_signal; 
         void Fred_memfn_wrapper() { object_which_will_handle_signal->memfn(); } 
 
         main() 
         { 
           /* signal(SIGINT, Fred::memfn); */   //不能这样做 
           signal(SIGINT, Fred_memfn_wrapper);  //Ok 
           signal(SIGINT, Fred::staticmemfn);   //Also Ok 
         } 
 
注意:静态成员函数不需要真正的物件才能启动,所以指向静态成员函数的指标,和 
普通的指向函数的指标,具有相容的型态(详见 ARM ["Annotated Reference 
Manual"] p.25, 158)。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:51
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
当我想以成员函数做为中断服务常式 (ISR) 时,为什麽编译器产生(型态不 
       符)的错误? 
 
这是前两个问题的特例,所以请先看看前两则解答。 
 
非静态的成员函数,都有一个隐藏的参数,对应到 'this' 指标,该 'this' 指标会 
指向该物件的案例资料 (instance data),可是系统中断的硬体/韧体并未提供这个 
'this' 参数。你得用「正常的」函数(不是类别的成员)或是静态成员函数来做为 
中断服务常式才行。 
 
一个可行的解法是:用一个静态成员做为中断服务常式,让它能自己到某处去找案例 
/成员的配对,以供中断呼叫之用。这麽一来,当中断产生时,正常的 method 就会 
被启动,不过以技术观点来看,你得先呼叫一个中介函数。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:51
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
为什麽我取不出 C++ 函数的位址? 
 
这可由前一则 FAQ 推论过来。 
 
详细的解答:在 C++ 里,成员函数有一个隐含的参数,指向该物件本身(成员函数 
内的 "this" 指标)。正常的 C 函数与成员函数的呼叫惯例可视为不同,所以它们 
指标的型态(指向成员函数 vs 指向函数)既不同也不相容。C++ 引进一个新的指标 
型态:指向成员的指标,要提供一个物件才能启动之(见 ARM ["Annotated 
Reference Manual"] 5.5)。 
 
注意:不要去把指向成员函数的指标强制转型成指向函数的指标;这样做的结果是未 
定义的,且下场可能会很惨。譬如,指向成员函数的指标,“不必然”会包含某正常 
函数的机器位址(看 ARM, 8.1.2c, p.158)。如前例所提,如果你有个指向正常 C 
函数的指标的话,请用上层的(非成员的)函数,或是用 "static" 成员函数(类别 
成员函数)。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:51
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样宣告指向成员函数的指标阵列? 
 
用 "typedef" 好让你的脑筋保持清醒。 
 
         class Fred { 
         public: 
           int f(char x, float y); 
           int g(char x, float y); 
           int h(char x, float y); 
           int i(char x, float y); 
           //... 
         }; 
 
         typedef  int (Fred::*FredPtr)(char x, float y); 
 
这是指向成员函数的指标阵列:Here's the array of pointers to member functions: 
 
         FredPtr a[4] = { &Fred::f, &Fred::g, &Fred::h, &Fred::i }; 
 
呼叫物件 "fred" 的某一个成员函数: 
 
         void userCode(Fred& fred, int methodNum, char x, float y) 
         { 
           //假设 "methodNum" 在 [0,3] 区间内 
           (fred.*a[methodNum])(x, y); 
         } 
 
你可以用 #define 让这个呼叫清楚些: 
 
         #define  callMethod(object,ptrToMethod)   ((object).*(ptrToMethod)) 
         callMethod(fred, a[methodNum]) (x, y); 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:52
快速回复:推荐:C++语言常见问题解答
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020903 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved