博文
C++中的名字查找(2007-10-18 09:43:00)
摘要:本文引用自:Herb Sutter 中文博客
原文地址:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1677385
Vijay Visana最近发邮件问我两个问题。内容如下(为了更适合阅读,我做了简单修改。译者在此基础上又做了修改):
我在C++的多继承上遇到了很大麻烦。
如图1,A、B1和B2为纯抽象类;C从B1、B2多继承,且实现了全部父类的抽象方法。
现在:
C* p = new C;
p->Method_of_A(); //从B1、B2都能得到被调用方法,为什么编译器不报“二义性”(ambiguity)错误呢?
而按图2结构实现继承关系后:
B4* p = new C;
p->Method_of_A();
编译器(VC++)认为有二义性。经调试我发现编译过程中使用了“adjustor thunk”(译者注:具体请参看http://blog.sina.com.cn/u/491874bb010004xq或Stan Lippman的《Inside the C++ Object Model》)。希望您能解答这两个问题,以帮助我更好理解C++(更确切的说是VC++)中的MI(多继承)机制。
好,我们深入研究下这个问题。
上述编译器行为的差异,与继承关系的复杂度、vtable以及adjustor thunk并无直接关系,它其实就是一个名字查找(name lookup)过程(以本例而言,就是查找方法“Method_of_A”)。
在C++中,函数编译时检查过程如下:
第一步,执行名字查找(name lookup):在调用类中查找,并生成候选列表;若候选列表为空,再扩大查找范围(如名字空间内,或父类);如此循环。如果最终无结果,那么抱歉,就会提示你“名字未能找到”;否则,编译器跳到第二步。
第二步,执行重载辨别(overload resolution):如果第一步得到的候选者个数大于一,编译器将以传递给函数的参数及其类型为依据,尝试找到最佳答案。如果无法据此确定最优者,就会报告“存在二义性调用”。
第三步,可见性检查(accessibility checking):编译器检查是否可真正执行调用(比如,......
笑话(2007-09-27 11:23:00)
摘要:太阳公司的一个JAVA程序员与其女友恋爱多年,就要结婚了,可是结婚第二天,其女友就提出离婚。
众人纳闷,何故?
其女友曰:他没有指针。
此JAVA程序员诧异的说:要指针干什么用?指针不安全!这是JAVA之父教导我们的,他说:“指针不安全!把你们的指针全割了吧”。
众狂笑,曰,要告诉所有的女网友,千万别找JAVA程序员,他们没有指针。
于是:百万名JAVA程序员被女友抛弃
--------------继续----------
JAVA程序员跑到太阳公司大闹起来,“连指针都没有,你凭什么叫太阳公司”,要求SUN公司还给他们指针。
于是太阳公司后来就拼凑出了一个半吊子指针给了这些JAVA程序员。
-----------再继续--------------
ASM/C/C++社区的程序员说:“没有指针,你怎么享受用指针的快乐呢?”
这些JAVA程序员们后悔末及,起诉了太阳公司,说,你也能叫日公司?!
但是还是有一些JAVA程序员当起了阿Q,认为当太监挺好,仍然重复着,“没有指针,多么安全呀”,而且还拉拢别人也割了指针来当JAVA程序员,但是上当的人越来越少了。
-----------继续3--------------
JAVA程序员的指针被日公司割掉了,
后来一个日人做了RUBY语言,中文谐音就是…………哈哈。
于是这些JAVA程序员就成天RUBYRUBY挂在口头上。
......
模板杂记(2007-09-27 10:29:00)
摘要:本文专门记录学习过程中碰到的关于模板的一些技巧:
1. 使用IsOfClassType类判断一个数据类型是否是class。
template<typename T> class IsOfClassType {
public:
template<typename U> static char check(int U::*);
template<typename U> static float check(...);
public:
enum { Result = sizeof(check<T>(0)) };
};
2.
template <typename _T>
class A{};
class B: public A< B >{
};
3.强制类型转换
template<typename dst_type,typename src_type>
dst_type union_cast(src_type src) {
union {
src_type src;
dst_type dst;
} u = {src};
return u.dst;
}
4.编译期计算数组元素个数
template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper( _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*_......
关于static成员变量(2007-09-03 10:00:00)
摘要:一直以为对static成员变量还算了解。直到昨晚看了《Effective C++》3rd Item49,才发现自己其实什么都不懂,真是惭愧!所以写下这篇随笔,为以后定期回顾参考,也希望大家不要犯类似的错误。
先看以下代码:
#include <iostream>
using namespace std;
class Base{
static int itest;
public:
void Set(){
itest++;
}
void Show(){
cout << itest << endl;
&nbs......
为数字加逗号分割(2007-08-30 15:22:00)
摘要:bruceteen的方法(使用一个如此设置的local):
#include <iostream>
#include <locale>
int main( void )
{
using namespace std;
cout << 1389992 << endl; // 1389992
locale chs( "chs" ); // chs在我这里行,不知道你那里怎么样
cout.imbue( chs );
cout << 1389992 << endl; // 1,389,992
}
特别推荐 namtso的方法(自己订制local):
#include <iostream>
#include <string>
#include <locale>
using namespace std;
class thousands_sep_facet:public std::numpunct<char>
{
public:
explicit thousands_sep_facet( size_t r=0 ) : std::numpunct<char>(r)
{
}
protected:
string do_grouping() const
{
return "\003";
}
};
int main( void )
{
cout << 1389992......
判断一个类中是否有某种类形(2007-08-28 09:56:00)
摘要:typedef char RT1;
typedef struct
{
char a[ 2 ];
} RT2;
//去引用
template < typename T >
class NonRef{
public:
typedef T NonRefX;
};
template < typename T >
class NonRef< T& >{
public:
typedef T NonRefX;
};
// 选择这个版本返回值大小为1
template < typename T > RT1 test( typename NonRef< typename T::X >::NonRefX const * )
{
int dumy = 0 ;
dumy ++ ;
}
// 选择这个版本返回值大小为2
template < typename T > RT2 test(...)
{
int dumy = 0 ;
dumy ++ ;
}
// 依靠编译器自动选择test函数,然后依据返回类型判断是否含有X
template < typename T >
bool type_has_member_type_X()
{
return ( sizeof (test < T > ( 0 )) == 1 );
}
// 有X类型的类
class HasX
{
public :
typedef int& X;
} ;
// 无X类型的类
class NonX
{
public :
class Y
{
} ;
} ;
int _tmain(int argc, _TCHAR*......
C++回调(CallBack)方案 (2007-08-17 12:03:00)
摘要:跟诸如Object Pascal和Ada等其它一些语言不同,C++语言并没有内在地提供一种将类的方法作为回调函数使用的方案。在C语言中,这种回调函数被称作算子(functor),在事件驱动类程序中普遍存在。主要问题基于这样一个事实:某个类的多个实例各自位于内存的不同位置。这就需要在回调的时候不仅需要一个函数指针,同时也需要一个指针指向某个实例本身(译者注:否则回调时便无法知道目前正在操作的是哪个对象,C++类的非静态方法包含一个默认的“参数”:this指针,就是起这种作用的)。所以,针对问题的定义,有一个很直观的解决方法就是使用模板和编译时的实例化及特化。
解决方案
这里的方案只支持一个模板参数,但如果一些能够如愿的话,随着更多的编译器完全实现C++标准,以后将会支持动态的模板参数,比如“…”形式的模板参数列表(参见《C++ Templates, The Complete Guide》),那时,我们就可以可以实现无需全部预定义的参数集合。(文中所有代码的注释为译者加,下同。)
template < class Class, typename ReturnType, typename Parameter >
class SingularCallBack
{
public:
//指向类成员函数的指针,用他来实现回调函数。
typedef ReturnType (Class::*Method)(Parameter);
//构造函数
SingularCallBack(Class* _class_instance, Method _method)
{
class_instance = _class_instance;
&nb......
c++ 重载决议与可访问性检查 (2007-08-07 09:23:00)
摘要:引用自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1406781
对于如下的类:
class ClxECS
{
public:
double Test(double dValue) { return dValue * 13; };
private:
int Test(int iValue) { return iValue * 13; };
};
下面的函数输出是什么?
void ECS_test()
{
int iValue = 13;
ClxECS lx;
cout << lx.Test(iValue) << endl;
}
如果说你的答案是169,那么你就大错特错了!
因为上面的函数根本不能通过编译!编译器会给你一个不能访问私有成员的错误。
惊奇吗?难道编译器不能找到类ClxECS的公有成员函数double Test(double dValue)并把实参iValue类型转换为double吗?
答案是:不能!其实原因很简单:C++中重载决议是在可访问性检查之前进行的。
对于上面的例子,编译是按如下顺序进行的:
首先,编译器进行重载决议,去查找适合的成员函数(而不管查找到的成员函数是否为pu......
typedef的四个用途和两个陷阱(2007-06-21 11:30:00)
摘要:转自:赤龙的BLOG
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
// 和一个字符变量;
以下则可行:
typedef char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,则可以直接写:结构名 对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
有关 Windows Mobile 5.0 模拟器的网络配置(2007-03-17 11:23:00)
摘要:本文来自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1190833
Step 1:配置面板-〉网络连接-〉右键点击Local Area Connection图标-〉属性。进入(图一)配置界面。
Step 2:如果已经存在红线标示的服务,则点击卸载,将其卸载掉。
Step 3:安装虚拟网卡驱动netsvwrap.msi,可以到MS的网站down一个。
Step 4:再次进入图一所示界面,会发现刚刚卸载的那个服务又出现了,这一次勾选该服务(即激活该服务),确定、退出。
Step 5:启动Visual Studio 2005,菜单选择:Tools-〉Options-〉Device Tools->Devices.在右侧的模拟器列表中选中要配置的模拟器,点击Properties按钮,进入模拟器配置界面。
Step 6:按下图所示配置。
Step 7:点击Emulator Options按钮。进入模拟器配置界面,点选NetWork标签。作如下配置:
Step 8:启动相应模拟器。配置模拟器:Start-〉Setting-〉Connections-〉Network Cards,进入(图 四)所示界面。
Step 9:将My network card connects to:置为 The Internet,并点击(图 四)红线所标示的选项。进入(图 五)界面。设置模拟器IP和网关以及DNS(下图只是举个例子,实际的设置需要你所处的网络环境来做,模拟器相当于和你的PC同处在一个网络内的机器)。确定。
Step 10:点击模拟器窗口菜单File-〉Configure->NetWork,若(图 七)红线标示选项未选中,则将其选中 OK;若该选项已经选中,则取消该选择,OK,并重新进入此界面将其选中,OK。
Step 11:Software Reset 模拟器。
Step 12:大功告成!......