科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件ATL布幔下的秘密之模板技术

ATL布幔下的秘密之模板技术

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

如果你是个模板的高手,你就可以将ATL的学习作为一种享受。在这一节中,我将要尝试解释一些ATL使用的模板技术.

作者:李马编译 来源:VCKBASE 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
在模板的帮助下,我们可以实现与之相同的行为。

  程序50.

#include <iostream>
using namespace std;

template <typename T>
class Base {
public:
void fun() {
cout << "Base::fun" << endl;
}

void doSomething() {
T* pT = static_cast<T*>(this);
pT->fun();
}
};

class Drive : public Base<Drive> {
public:
void fun() {
cout << "Drive::fun" << endl;
}
};

int main() {
Drive obj;
obj.doSomething();

return 0;
}
  
  程序的输出和前一个是一样的,所以我们可以用模板来模拟虚函数的行为。

  程序中一个有趣的地方为:

class Drive : public Base<Drive> {
这表明我们可以将Drive类作为一个模板参数来传递。程序中另外一个有趣的地方是基类中的doSomething函数。
T* pT = static_cast<T*>(this);
pT->fun();

  在这里基类的指针被转换为派生类的指针,因为派生类是作为Base类的模板参数传递的。这个函数可以通过指针来执行,由于指针指向了派生类的对象,所以派生类的对象就被调用了。

  但是这就有一个问题了:我们为什么要这样做?答案是:这样可以节省虚函数带有的额外开销,也就是虚函数表指针、虚函数表以及节省了调用虚函数所花费的额外时间。这就是ATL中使组件尽可能小、尽可能快的主要思想。

  现在,你的脑海中可能会浮现另外一个问题。如果依靠这一开销更少的技术可以模拟虚函数的话,那我们为什么还要调用虚函数呢?我们不应该用这一技术替换所有的虚函数吗?对于这一问题,我可以简短地回答你:不,我们不能用这一技术替换虚函数。

  其实这一技术还存在一些问题。第一,你不能从Drive类进行更深层的继承,如果你试着这么做,那么它将不再会是虚函数的行为了。而对于虚函数来说,这一切就不会发生。一旦你将函数声明为虚函数,那么在派生类中的所有函数都会成为虚函数,无论继承链有多深。现在我们看看当从Drive中再继承一个类的时候会发生什么。

  程序51.

#include <iostream>
using namespace std;

template <typename T>
class Base {
public:
void fun() {
cout << "Base::fun" << endl;
}

void doSomething() {
T* pT = static_cast<T*>(this);
pT->fun();
}
};

class Drive : public Base<Drive> {
public:
void fun() {
cout << "Drive::fun" << endl;
}
};

class MostDrive : public Drive {
public:
void fun() {
cout << "MostDrive::fun" << endl;
}
};

int main() {
MostDrive obj;
obj.doSomething();

return 0;
}

  程序的输出和前一个一样。但是对于虚函数的情况来说,输出就应该是: MostDrive::fun

  这一技术还有另外一个问题,就是当我们使用Base类的指针来存储派生类的地址的时候。

  程序52.

#include <iostream>
using namespace std;

template <typename T>
class Base {
public:
void fun() {
cout << "Base::fun" << endl;
}

void doSomething() {
T* pT = static_cast<T*>(this);
pT->fun();
}
};

class Drive : public Base<Drive> {
public:
void fun() {
cout << "Drive::fun" << endl;
}
};

int main() {
Base* pBase = NULL;
pBase = new Drive;

return 0;
}

  这个程序会给出一个错误,因为我们没有向基类传递模板参数。现在我们稍微修改一下,并传递模板参数。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章