problem, you will implement a no virtual base class template using the Curiously Recurring Template Pattern n this or CRTP Your task is to define the Comparable template, implementing the following functions in terms of the Derived class operator<: operator operator operator operator operator Additionally, each function should be noexcept and const-qualified.
Please use C++.
And also I want a answer implementint the functions in term of the Derived class operator<.
There is a question on this website before but I do not think that answer is good enough.
// 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; } |
Output :
Time taken: 2613 nanoseconds
See this for above result.
When a method is declared virtual, compiler secretly does two things for us:
What are VTable and VPtr?
When a method is declared virtual in a class, compiler creates a
virtual table (aka VTable) and stores addresses of virtual methods
in that table. A virtual pointer (aka VPtr) is then created and
initialized to point to that VTable. A VTable is shared across all
the instances of the class, i.e. compiler creates only one instance
of VTable to be shared across all the objects of a class. Each
instance of the class has its own version of VPtr. If we print the
size of a class object containing at least one virtual method, the
output will be sizeof(class data) + sizeof(VPtr).
Since address of virtual method is stored in VTable, VPtr can be
manipulated to make calls to those virtual methods thereby
violating principles of encapsulation. See below example:
// 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; } |
Output :
CDerived::Foo() called CBase::Foo() called
We are able to access vPtr and able to make calls to virtual methods through it. The memory representation of objects is explained here.
Is it wise to use virtual method?
As it can be seen, through base class pointer, call to derived
class method is being dispatched. Everything seems to be working
fine. Then what is the problem?
If a virtual routine is called many times (order of hundreds of
thousands), it drops the performance of system, reason being each
time the routine is called, its address needs to be resolved by
looking through VTable using VPtr. Extra indirection (pointer
dereference) for each call to a virtual method makes accessing
VTable a costly operation and it is better to avoid it as much as
we can.
Curiously Recurring Template Pattern (CRTP)
Usage of VPtr and VTable can be avoided altogether through
Curiously Recurring Template Pattern (CRTP). CRTP is a design
pattern in C++ in which a class X derives from a class template
instantiation using X itself as template argument. More generally
it is known as F-bound polymorphism.
// Image program (similar to above) to demonstrate // working of CRTP #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. The template // parameter T is used to know type of derived // class pointed by pointer. template <class T> class Image { public: void Draw() { // Dispatch call to exact type static_cast<T*> (this)->Draw(); } Dimension GetDimensionInPixels() { // Dispatch call to exact type static_cast<T*> (this)->GetDimensionInPixels(); } protected: int dimensionX, dimensionY; }; // For Tiff Images class TiffImage : public Image<TiffImage> { public: void Draw() { // Uncomment this to check method dispatch // cout << "TiffImage::Draw() called" << endl; } Dimension GetDimensionInPixels() { return Dimension(dimensionX, dimensionY); } }; // There can be more derived classes like PngImage, // BitmapImage, etc // Driver code int main() { // An Image type pointer pointing to Tiffimage Image<TiffImage>* 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; } |
Output :
Time taken: 732 nanoseconds
See this for above result.
Virtual method vs CRTP benchmark
The time taken while using virtual method was 2613 nanoseconds.
This (small) performance gain from CRTP is because the use of a
VTable dispatch has been circumvented. Please note that the
performance depends on a lot of factors like compiler used,
operations performed by virtual methods. Performance numbers might
differ in different runs, but (small) performance gain is expected
from CRTP.
Note: If we print size of class in CRTP, it can bee seen that VPtr
no longer reserves 4 bytes of memory.
cout << sizeof(Image) << endl;
problem, you will implement a no virtual base class template using the Curiously Recurring Template Pattern...
c++
Part 1 Consider using the following Card class as a base class to implement a hierarchy of related classes: class Card { public: Card(); Card (string n) ; virtual bool is_expired() const; virtual void print () const; private: string name; Card:: Card() name = ""; Card: :Card (string n) { name = n; Card::is_expired() return false; } Write definitions for each of the following derived classes. Derived Class Data IDcard ID number CallingCard Card number, PIN Driverlicense Expiration date...
(The SortedLinkedList class template) Complete the SortedLinkedList class template which is a doubly linked list and is implemented with a header node and a tail node. // SortedLinkedList.h // SortedLinkedList.h // A collection of data are stored in the list by ascending order #ifndef SORTEDLIST_H #define SORTEDLIST_H using namespace std; template <typename T> class SortedList { private: // The basic single linked list node type. // Nested inside of SortedList. struct NodeType { T data; NodeType* next; NodeType* prev; NodeType(const...
For this computer assignment, you are to write a C++ program to implement a class for binary trees. To deal with variety of data types, implement this class as a template. The definition of the class for a binary tree (as a template) is given as follows: template < class T > class binTree { public: binTree ( ); // default constructor unsigned height ( ) const; // returns height of tree virtual void insert ( const T& ); //...