ATL中值得注意的C++技术
2006-09-06 12:31
288 查看
1. 多重继承中的名字冲突问题。
class father {
virtual int faint() { return 0; }
};
class mother {
virtual int faint() { return 1; }
};
class baby : public father, public mother {
...
virtual int father::faint() { return 2; }
virtual int mother::faint() { return 3; }
//错误,无法区别father::faint和mother::faint。
};
既然father和baby两个类中的faint都是virtual的,那么应该都可以重载了。
但是这一点总是渴望不可及,因为无法决议。C++的标准解法之一就是声明两个辅助的类。
class _father : public father {
virtual int faint() { return fatherfaint(); }
virtual int fatherfaint() = 0;
};
class _mother : public mother {
virtual int faint() { return motherfaint(); }
virtual int motherfaint() = 0;
};
class baby : public _father, public _mother {
...
//在这里重载fatherfaint和motherfaint两个函数
virtual int fatherfaint() {..}
virtual int motherfaint() {..}
};
但是这样的做法并不是非常好。如果baby这个类重载了faint()函数,那么fatherfaint()和motherfaint()都被遮掩了;如果baby这个类没有重载faint()函数,那么baby就没有办法faint()了,因为他无法决议faint()这个函数来自哪里。仔细想想这还是很合乎逻辑的。孩子生下来谁知道是象爸爸还是象妈妈呢?
[ 深入解析ATL pp 216 ] 很遗憾这个作者没有看过Scott Mayer的Effective C++。 ;((
[ Effective C++ item 43 ]
但是ATL的考虑效率更多一些,而上面的方法多了一层虚函数的调用。所以它提供了不是很pp的解法。
template<class Deriving>
struct ATL_NO_VTABLE _father : public father {
virtual int faint() {
return static_cast<Deriving*>(this)->fatherfaint(); }
};
template<class Deriving>
struct ATL_NO_VTABLE _mother : public mother {
virtual int faint() {
return static_cast<Deriving*>(this)->motherfaint(); }
};
class baby : public _father<baby>, public _mother<baby> {
...
};
ATL_NO_VTABLE是一个宏,定义可以看MSDN:
#ifdef _ATL_DISABLE_NO_VTABLE
#define ATL_NO_VTABLE
#else
#define ATL_NO_VTABLE __declspec(novtable)
#endif
这里直接理解做 __declspec(novtable),指明这个类在构造和析构的时候抹掉vtable。注意到类当中根本没有用到vtable,所以抹掉就抹掉吧,无所谓了。这个方法虽然也是万能的,但是在不支持novtable的编译器上作优化却是万万不能。比如gcc。;(
顺便一提的还有所谓的着色技术。以上问题之所以是一个问题是因为编译过程中产生了名字冲突。如果名字不同那就无所谓名字冲突了,而且执行期的程序也不是用名字来查找函数的。因此如果我们上述体系中还有一个中间层,那么你就可以在中间层中耍点小花样来骗过编译器:声明一个新的类而不是从原来的类中继承,保证新的类中函数的摆放和继承回来的类是一样的,同时把名字改一下。这种方法已经过气了,多说无益,不提也罢。
class father {
virtual int faint() { return 0; }
};
class mother {
virtual int faint() { return 1; }
};
class baby : public father, public mother {
...
virtual int father::faint() { return 2; }
virtual int mother::faint() { return 3; }
//错误,无法区别father::faint和mother::faint。
};
既然father和baby两个类中的faint都是virtual的,那么应该都可以重载了。
但是这一点总是渴望不可及,因为无法决议。C++的标准解法之一就是声明两个辅助的类。
class _father : public father {
virtual int faint() { return fatherfaint(); }
virtual int fatherfaint() = 0;
};
class _mother : public mother {
virtual int faint() { return motherfaint(); }
virtual int motherfaint() = 0;
};
class baby : public _father, public _mother {
...
//在这里重载fatherfaint和motherfaint两个函数
virtual int fatherfaint() {..}
virtual int motherfaint() {..}
};
但是这样的做法并不是非常好。如果baby这个类重载了faint()函数,那么fatherfaint()和motherfaint()都被遮掩了;如果baby这个类没有重载faint()函数,那么baby就没有办法faint()了,因为他无法决议faint()这个函数来自哪里。仔细想想这还是很合乎逻辑的。孩子生下来谁知道是象爸爸还是象妈妈呢?
[ 深入解析ATL pp 216 ] 很遗憾这个作者没有看过Scott Mayer的Effective C++。 ;((
[ Effective C++ item 43 ]
但是ATL的考虑效率更多一些,而上面的方法多了一层虚函数的调用。所以它提供了不是很pp的解法。
template<class Deriving>
struct ATL_NO_VTABLE _father : public father {
virtual int faint() {
return static_cast<Deriving*>(this)->fatherfaint(); }
};
template<class Deriving>
struct ATL_NO_VTABLE _mother : public mother {
virtual int faint() {
return static_cast<Deriving*>(this)->motherfaint(); }
};
class baby : public _father<baby>, public _mother<baby> {
...
};
ATL_NO_VTABLE是一个宏,定义可以看MSDN:
#ifdef _ATL_DISABLE_NO_VTABLE
#define ATL_NO_VTABLE
#else
#define ATL_NO_VTABLE __declspec(novtable)
#endif
这里直接理解做 __declspec(novtable),指明这个类在构造和析构的时候抹掉vtable。注意到类当中根本没有用到vtable,所以抹掉就抹掉吧,无所谓了。这个方法虽然也是万能的,但是在不支持novtable的编译器上作优化却是万万不能。比如gcc。;(
顺便一提的还有所谓的着色技术。以上问题之所以是一个问题是因为编译过程中产生了名字冲突。如果名字不同那就无所谓名字冲突了,而且执行期的程序也不是用名字来查找函数的。因此如果我们上述体系中还有一个中间层,那么你就可以在中间层中耍点小花样来骗过编译器:声明一个新的类而不是从原来的类中继承,保证新的类中函数的摆放和继承回来的类是一样的,同时把名字改一下。这种方法已经过气了,多说无益,不提也罢。
相关文章推荐
- C & C++ 中值得注意的编译,链接,调试,错误及其原因
- 学习C++值得注意的问题
- c++ 函数值得注意的地方!
- C++ 11几个值得注意的特性 —— 从Techparty新语言回来有感(1)
- 值得推荐的C/C++框架和库
- C++ trick之重载类型转换操作符 “orthodox”技术
- C++技术问题总结-第13篇 调用约定有哪些,有什么不同
- 从c++转到Python需要注意的地方
- 值得推荐的C/C++框架和库
- 值得推荐的C/C++框架和库 (真的很强大)
- c++和c的注意点和不同点:
- ajax post中在firefox返回值一个值得注意的地方
- windows 64位技术--C/C++的64位移植
- C++中的Vector操作注意点
- c++返回值 注意事项
- JAVA值得注意继承简单例子..
- C++技术总结
- C/C++中的指针的应用及注意问题
- TEC1401.Report开发技术总结 - 第五章 使用Oracle Reports开发报表-在EBS应用中注册Report的注意事项(4/4)
- boost库之Hash - 兔子的技术博客 - C++博客