热门关键词:

软件设计奇怪的重复模板模式(CRTP)

添加时间:2019-09-05 15:42:44

来源:

浏览:

建议将虚函数和运行时多态性作为先决条件。下面是一个演示运行时多态性的示例程序。

filter_none

编辑

play_arrow


brightness_4

// A simple C++ program to demonstrate run-time  

// polymorphism 

#include <iostream> 

#include <chrono> 

using namespace std; 

  

typedef std::chrono::high_resolution_clock Clock; 

  

// To store dimensions of an image 

class Dimension 

public: 

    Dimension(int _X, int _Y) {mX = _X;  mY = _Y; } 

private: 

    int mX, mY; 

}; 

  

// Base class for all image types 

class Image 

public: 

    virtual void Draw() = 0; 

    virtual Dimension GetDimensionInPixels() = 0; 

protected: 

    int dimensionX; 

    int dimensionY; 

}; 

  

// For Tiff Images 

class TiffImage : public Image 

public: 

    void Draw() { } 

    Dimension GetDimensionInPixels() { 

        return Dimension(dimensionX, dimensionY); 

    } 

}; 

  

// There can be more derived classes like PngImage,  

// BitmapImage, etc 

  

// Driver code that calls virtual function 

int main() 

    // An image type   

    Image* pImage = new TiffImage; 

  

    // Store time before virtual function calls 

    auto then = Clock::now(); 

  

    // Call Draw 1000 times to make sure performance 

    // is visible 

    for (int i = 0; i < 1000; ++i) 

        pImage->Draw(); 

  

    // Store time after virtual function calls 

    auto now = Clock::now(); 

  

    cout << "Time taken: "

         << std::chrono::duration_cast 

           <std::chrono::nanoseconds>(now - then).count() 

         << " nanoseconds" << endl; 

  

    return 0; 

输出:


所用时间:2613纳秒

见这对上述结果。


当一个方法被声明为虚拟时,编译器会秘密为我们做两件事:


在类对象的前4个字节中定义VPtr

在构造函数中插入代码以初始化VPtr以指向VTable

什么是VTable和VPtr?

当一个方法在类中声明为virtual时,编译器会创建一个虚拟表(也称为VTable)并在该表中存储虚方法的地址。然后创建虚拟指针(也称为VPtr)并初始化以指向该VTable。VTable在类的所有实例之间共享,即编译器仅创建一个VTable实例,以便在类的所有对象之间共享。该类的每个实例都有自己的VPtr版本。如果我们打印包含至少一个虚方法的类对象的大小,则输出将是sizeof(类数据)+ sizeof(VPtr)。

由于虚拟方法的地址存储在VTable中,因此可以操纵VPtr以调用那些虚拟方法,从而违反封装原则。见下面的例子:


filter_none

编辑

play_arrow


brightness_4

// A C++ program to demonstrate that we can directly 

// manipulate VPtr. Note that this program is based  

// on the assumption that compiler store vPtr in a  

// specific way to achieve run-time polymorphism. 

#include <iostream> 

using namespace std; 

  

#pragma pack(1) 

  

// A base class with virtual function foo() 

class CBase 

public: 

    virtual void foo() noexcept { 

        cout << "CBase::Foo() called" << endl; 

    } 

protected: 

    int mData; 

}; 

  

// A derived class with its own implementation 

// of foo()  

class CDerived : public CBase 

public: 

    void foo() noexcept  { 

        cout << "CDerived::Foo() called" << endl; 

    } 

private: 

    char cChar; 

}; 

  

// Driver code 

int main() 

    // A base type pointer pointing to derived 

    CBase *pBase = new CDerived; 

  

    // Accessing vPtr 

    int* pVPtr = *(int**)pBase; 

  

    // Calling virtual method 

    ((void(*)())pVPtr[0])(); 

  

    // Changing vPtr 

    delete pBase; 

    pBase = new CBase; 

    pVPtr = *(int**)pBase; 

  

    // Calls method for new base object 

    ((void(*)())pVPtr[0])(); 

  

    return 0; 

输出:


CDerived :: Foo()调用

调用CBase :: Foo() 

我们能够访问vPtr并能够通过它调用虚拟方法。这里解释了对象的内存表示。


使用虚方法是明智的吗?

可以看出,通过基类指针,正在调度派生类方法。一切似乎都很好。那有什么问题呢?

如果多次调用虚拟例程(数十万的顺序),则会降低系统性能,原因是每次调用例程时,需要通过使用VPtr查看VTable来解析其地址。对虚拟方法的每次调用的额外间接(指针取消引用)使得访问VTable成为一项代价高昂的操作,最好尽可能地避免它。


用户名 Name
评论 Comment

软件开发  相关内容

——
05

2019-09

奇怪的重复模板模式(CRTP)

通过奇怪的重复模板模式(CRTP)可以完全避免使用VPtr和VTable。CRTP是C ++中的一种设计模式,其中类X派生自使用X本身作为模板参数的类模板实例化。更一般地,它被称为F结合多态性。filter_none编辑play_arrowbrightness_4// Image… [了解更多]

05

2019-09

软件设计奇怪的重复模板模式(CRTP)

建议将虚函数和运行时多态性作为先决条件。下面是一个演示运行时多态性的示例程序。filter_none编辑play_arrowbrightness_4// A simple C++ program to demonstrate run-time// polymorphism#inc…… [了解更多]

02

2019-08

app开发公司的软件设计的迭代器模式

迭代器模式是一种相对简单且经常使用的设计模式。每种语言都有很多数据结构/集合。每个集合都必须提供一个迭代器,让迭代器遍历其对象。但是,在执行此操作时,应确保它不会公开其实现。假设我们正在构建一个需要我们维护通知列表的应用程序。最终,您的代码的某些部分将需要迭代所有通知。如果我们将… [了解更多]

03

2019-07

纪念差一点改变世界的coreseek的错

Coreseek 是一款中文全文检索/搜索软件,以GPLv2许可协议开源发布,基于Sphinx研发并独立发布,专攻中文搜索和信息处理领域,适用于行业/垂直搜索、论坛/站内搜索、数据库搜索、文档/文献检索、信息检索、数据挖掘等应用场景,用户可以免费下载使用整理了coreseek/s… [了解更多]

24

2019-06

软件开发如何防止反射,序列化和克隆的单例

反射: 可以导致反射破坏单例类的单例属性,如下例所示:filter_none编辑play_arrowbrightness_4// Java code to explain effect of Reflection// on Singleton propertyimport jav…… [了解更多]

关注

成都软件开发

  • 地 址:成都市人民南路四段成科西路三号 863国家孵化园
  • 电 话:18215 660330
  • 手机:18215 660330
  • 传 真:18215 660330
  • 邮 箱:179001057@qq.com
  • 邮政编码:610000