c++

44
It is not Const. pointer in copy constructor but const Reference of object of same class type which we do pass in copy constructor.... and everyone has given pretty good answers for two questions 1) what is importance of const. reference object of same class type in copy const... 2) Why do we use reference of class instead of simple pass by value. Again one query why dont we use pass by pointer in copy constructor so see following scenario class ABC { public: ABC(){} /*Simple Constructor*/ ABC(ABC * b) { }/*Copy Constructor*/ }; int main(int argc, char* argv[]){ ABC * d1 = NULL; ABC d2 = d1; /*Calling Copy constructor*/ return 0; } See above example , if we take pointer type object in copy constructor two flaws are here 1) We can assign NULL value to simple object of that class 2) see this line ABC d2 = d1; here d2 is ABC type while d1 is ABC* type means as per rule we are violating basic rules by allowing to assign simple type with pointer type. If there is any pointer type member variable in side ABC class means DEEP Copy scenario like int * m_iVal; then it will crash out during calling copy constructor by passing NULL object... so stop such mistake at design time we do use const reference object of same class type in copy constructor as a parameter.Hoping this will clear you Copy constructor Complier provide by default shallow copy … User copy constructor provide shallow copy class Cents { private: int m_nCents; public: Cents(int nCents=0) { m_nCents = nCents; } // Copy constructor Cents(const Cents &cSource) { m_nCents = cSource.m_nCents; } Cents& operator= (const Cents &cSource); };

description

C++ docs

Transcript of c++

Page 1: c++

It is not  Const. pointer in copy constructor but const Reference of object of same class type which we do pass in copy constructor.... and everyone has given pretty good answers  for two questions1) what is importance of const. reference object of same class  type  in copy const...2) Why do we use reference of class instead of simple pass by value.Again one query why dont we use pass by pointer in copy constructor  so see following scenarioclass ABC{public:  ABC(){} /*Simple Constructor*/  ABC(ABC * b) { }/*Copy Constructor*/};int main(int argc, char* argv[]){  ABC * d1 = NULL;   ABC    d2 = d1; /*Calling Copy constructor*/  return 0;}See above example , if we take pointer type object in copy constructor  two flaws are here 1) We can assign NULL value to simple object of that class2) see this line  ABC    d2 = d1;here d2 is ABC type while d1 is ABC* type means as per rule we are violating basic rules by allowing to assign simple type with pointer type. If there is any pointer type member variable in side ABC class means DEEP Copy scenario like int * m_iVal; then it will crash out during calling copy constructor by passing NULL object... so stop such mistake at design time we do use const reference object of same class type in copy constructor as a parameter.Hoping this will clear you

Copy constructorComplier provide by default shallow copy …User copy constructor provide shallow copyclass Cents{private: int m_nCents;public: Cents(int nCents=0) { m_nCents = nCents; }

// Copy constructor Cents(const Cents &cSource) { m_nCents = cSource.m_nCents; }

Cents& operator= (const Cents &cSource);

};// Copy constructorMyString::MyString(const MyString& cSource){ // because m_nLength is not a pointer, we can shallow copy it m_nLength = cSource.m_nLength;

// m_pchString is a pointer, so we need to deep copy it if it is non-null if (cSource.m_pchString)

Page 2: c++

{ // allocate memory for our copy m_pchString = new char[m_nLength];

// Copy the string into our newly allocated memory strncpy(m_pchString, cSource.m_pchString, m_nLength); } else m_pchString = 0;}// Assignment operatorMyString& MyString::operator=(const MyString& cSource){ // check for self-assignment if (this == &cSource) return *this;

// first we need to deallocate any value that this string is holding! delete[] m_pchString;

// because m_nLength is not a pointer, we can shallow copy it m_nLength = cSource.m_nLength;

// now we need to deep copy m_pchString if (cSource.m_pchString) { // allocate memory for our copy m_pchString = new char[m_nLength];

// Copy the parameter the newly allocated memory strncpy(m_pchString, cSource.m_pchString, m_nLength); } else m_pchString = 0;

return *this;}

Preventing copyingSometimes we simply don’t want our classes to be copied at all. The best way to do this is to add the prototypes for the copy constructor and overloaded operator= to the private section of your class.class MyString{private: char *m_pchString; int m_nLength; MyString(const MyString& cSource); MyString& operator=(const MyString& cSource);public: // Rest of code here

Page 3: c++

};In this case, C++ will not automatically create a default copy constructor and default assignment operator, because we’ve told the compiler we’re defining our own functions. Furthermore, any code located outside the class will not be able to access these functions because they’re private.Summary

The default copy constructor and default assignment operators do shallow copies, which is fine for classes that contain no dynamically allocated variables.

Classes with dynamically allocated variables need to have a copy constructor and assignment operator that do a deep copy.

The assignment operator is usually implemented using the same code as the copy constructor, but it checks for self-assignment, returns *this, and deallocates any previously allocated memory before deep copying.

If you don’t want a class to be copyable, use a private copy constructor and assignment operator prototype in the class header.

Object slicing:

Example:class Shape {public:virtual double Area();…protected:double x, y;};class Rectangle : public Shape {public:virtual double Area();…private:double height, width;};int main() {Rectangle rect;Shape *ptr_rect = ▭Shape shape_rect = rect;ptr_rect->Area();shape_rect.Area();}Rectangle::Area()Shape::Area()shape_rect is an object sliceof rect. It contains justx and y, notheight and width

===============================CompositionBY ALEX, ON DECEMBER 4TH, 2007In real-life, complex objects are often built from smaller, simpler objects. For example, a car is built using a metal frame, an engine, some tires, a transmission, a steering wheel, and a large number of other parts. A personal computer is built from a CPU, a motherboard, some memory, etc… Even you are built from smaller parts: you have a head, a body, some legs, arms, and so on. This process of building complex objects from simpler ones is called composition (also known as object composition).

Page 4: c++

More specifically, composition is used for objects that have a has-a relationship to each other. A car has-a metal frame, has-anengine, and has-a transmission. A personal computer has-a CPU, a motherboard, and other components. You have-a head, a body, some limbs.So far, all of the classes we have used in our examples have had member variables that are built-in data types (eg. int, double). While this is generally sufficient for designing and implementing small, simple classes, it quickly becomes burdensome for more complex classes, especially those built from many sub-parts. In order to facilitate the building of complex classes from simpler ones, C++ allows us to do object composition in a very simple way — by using classes as member variables in other classes.Lets take a look at some examples of how this is done. If we were designing a personal computer class, we might do it like this (assuming we’d already written a CPU, Motherboard, and RAM class):

01 #include "CPU.h"

02 #include "Motherboard.h"

03 #include "RAM.h"

04  

05 class PersonalComputer

06 {

07 private:

08    CPU m_cCPU;

09    Motherboard m_cMotherboard;

10    RAM m_cRAM;

11 };Initializing class member variablesIn the previous lesson on initializer lists , you learned that the preferred way to initialize class members is through initializer lists rather than assignment. So let’s write a constructor for our PersonalComputer class that uses an initialization list to initialize the member variables. This constructor will take 3 parameters: a CPU speed, a motherboard model, and a RAM size, which it will then pass to the respective member variables when they are constructed.

1 PersonalComputer::PersonalComputer(int nCPUSpeed, char *strMotherboardModel, int nRAMSize)

2     : m_cCPU(nCPUSpeed), m_cMotherboard(strMotherboardModel), m_cRAM(nRAMSize)

3 {

4 }Now, when a PersonalComputer object is instantiated using this constructor, that PersonalComputer object will contain a CPU object initialized with nCPUSpeed, a Motherboard object initialized with strMotherboardModel, and a RAM object initialized with nRAMSize.It is worth explicitly noting that composition implies ownership between the complex class and any subclasses. When the complex class is created, the subclasses are created. When the complex class is destroyed, the subclasses are similarly destroyed.A full exampleWhile the above example is useful in giving the general idea of how composition works, let’s do a full example that you can compile yourself. Many games and simulations have creatures or objects that move around a board, map, or screen. The one thing that all of these creatures/objects have in common is that they all have-a location. In this example, we are going to create a creature class that uses a point class to hold the creature’s location.First, let’s design the point class. Our creature is going to live in a 2d world, so our point class will have 2 dimensions, X and Y. We will assume the world is made up of discrete squares, so these dimensions will always be integers.Point2D.h:#ifndef POINT2D_H#define POINT2D_H

#include <iostream>

Page 5: c++

class Point2D{private: int m_nX; int m_nY;

public: // A default constructor Point2D() : m_nX(0), m_nY(0) { }

// A specific constructor Point2D(int nX, int nY) : m_nX(nX), m_nY(nY) { }

// An overloaded output operator friend std::ostream& operator<<(std::ostream& out, const Point2D &cPoint) { out << "(" << cPoint.GetX() << ", " << cPoint.GetY() << ")"; return out; }

// Access functions void SetPoint(int nX, int nY) { m_nX = nX; m_nY = nY; }

int GetX() const { return m_nX; } int GetY() const { return m_nY; }};

#endifNote that because we’ve implemented all of our functions in the header file (for the sake of keeping the example concise), there is no Point2D.cpp.Now let’s design our Creature. Our Creature is going to have a few properties. It’s going to have a name, which will be a string, and a location, which will be our Point2D class.Creature.h:

#ifndef CREATURE_H#define CREATURE_H

#include <iostream>#include <string>#include "Point2D.h"

class Creature{private: std::string m_strName; Point2D m_cLocation;

// We don't want people to create Creatures with no name or location // so our default constructor is private Creature() { }

public: Creature(std::string strName, const Point2D &cLocation) : m_strName(strName), m_cLocation(cLocation) { }

friend std::ostream& operator<<(std::ostream& out, const Creature &cCreature) { out << cCreature.m_strName.c_str() << " is at " << cCreature.m_cLocation; return out; }

void MoveTo(int nX, int nY)

Page 6: c++

{ m_cLocation.SetPoint(nX, nY); }};#endif

Main.cpp#include <string>#include <iostream>#include "Creature.h"

int main(){ using namespace std; cout << "Enter a name for your creature: "; std::string cName; cin >> cName; Creature cCreature(cName, Point2D(4, 7));

while (1) { cout << cCreature << endl; cout << "Enter new X location for creature (-1 to quit): "; int nX=0; cin >> nX; if (nX == -1) break;

cout << "Enter new Y location for creature (-1 to quit): "; int nY=0; cin >> nY; if (nY == -1) break;

cCreature.MoveTo(nX, nY); }

return 0;}Here’s a transcript of this code being run:Enter a name for your creature: MarvinMarvin is at (4, 7)Enter new X location for creature (-1 to quit): 6Enter new Y location for creature (-1 to quit): 12Marvin is at (6, 12)Enter new X location for creature (-1 to quit): 3Enter new Y location for creature (-1 to quit): 2Marvin is at (3, 2)Enter new X location for creature (-1 to quit): -1Why use composition?Instead of using the Point2D class to implement the Creature’s location, we could have instead just added 2 integers to the Creature class and written code in the Creature class to handle the positioning. However, using composition provides a number of useful benefits:

1. Each individual class can be kept relatively simple and straightforward, focused on performing one task. This makes those classes easier to write and much easier to understand. For example, Point2D only worries about point-related stuff, which helps keep it simple.

2. Each subobject can be self-contained, which makes them reusable. For example, we could reuse our Point2D class in a completely different application. Or if our creature ever needed another point (for example, a destination it was trying to get to), we can simply add another Point2D member variable.

3. The complex class can have the simple subclasses do most of the hard work, and instead focus on coordinating the data flow between the subclasses. This helps lower the overall complexity of the complex object, because it can delegate tasks to the sub-objects, who already know how to do them. For example, when we move our Creature, it delegates that task to the Point class, which already understands how to set a point. Thus, the Creature class does not have to worry about how such things would be implemented.

One question that new programmers often ask is “When should I use composition instead of direct implementation of a feature?”. There’s no 100% answer to that question. However, a good rule of thumb is that each class should be built to accomplish a single task. That task should either be the storage and manipulation of some kind of data (eg. Point2D), OR the coordination of subclasses (eg. Creature). Not both.In this case of our example, it makes sense that Creature shouldn’t have to worry about how Points are implemented, or how the name is being stored. Creature’s job isn’t to know those intimate details. Creature’s job is to worry about how to coordinate the data flow and ensure that each of the subclasses knows what it is supposed to do. It’s up to the individual subclasses to worry about how they will do it.

Page 7: c++

AggregationBY ALEX, ON DECEMBER 7TH, 2007In the previous lesson on composition, you learned that compositions are complex classes that contain other subclasses as member variables. In addition, in a composition, the complex object “owns” all of the subobjects it is composed of. When a composition is destroyed, all of the subobjects are destroyed as well. For example, if you destroy a car, it’s frame, engine, and other parts should be destroyed as well. If you destroy a PC, you would expect it’s RAM and CPU to be destroyed as well.AggregrationAn aggregation is a specific type of composition where no ownership between the complex object and the subobjects is implied. When an aggregate is destroyed, the subobjects are not destroyed.For example, consider the math department of a school, which is made up of one or more teachers. Because the department does not own the teachers (they merely work there), the department should be an aggregate. When the department is destroyed, the teachers should still exist independently (they can go get jobs in other departments).Because aggregations are just a special type of compositions, they are implemented almost identically, and the difference between them is mostly semantic. In a composition, we typically add our subclasses to the composition using either normal variables or pointers where the allocation and deallocation process is handled by the composition class.#include <string>using namespace std;class Teacher{private: string m_strName;public: Teacher(string strName) : m_strName(strName) { }

string GetName() { return m_strName; }};

class Department{private: Teacher *m_pcTeacher; // This dept holds only one teacher

public: Department(Teacher *pcTeacher=NULL) : m_pcTeacher(pcTeacher) { }};

int main(){ // Create a teacher outside the scope of the Department Teacher *pTeacher = new Teacher("Bob"); // create a teacher { // Create a department and use the constructor parameter to pass // the teacher to it. Department cDept(pTeacher);

} // cDept goes out of scope here and is destroyed

// pTeacher still exists here because cDept did not destroy it delete pTeacher;}In an aggregation, we also add other subclasses to our complex aggregate class as member variables. However, these member variables are typically either references or pointers that are used to point at objects that have been created outside the scope of the class. Consequently, an aggregate class usually either takes the objects it is going to point to as constructor parameters, or it begins empty and the subobjects are added later via access functions or operators.Because these subclass objects live outside of the scope of the class, when the class is destroyed, the pointer or reference member variable will be destroyed, but the subclass objects themselves will still exist.Let’s take a look at our Teacher and Department example in more detail.In this case, pTeacher is created independetly of cDept, and then passed into cDept’s constructor. Note that the department class uses an initialization list to set the value of m_pcTeacher to the pTeacher value we passed in. When cDept is destroyed, the m_pcTeacher pointer destroyed, but pTeacher is not deallocated, so it still exists until it is independently destroyed.

Page 8: c++

To summarize the differences between composition and aggregation:Compositions:

Typically use normal member variables Can use pointer values if the composition class automatically handles allocation/deallocation Responsible for creation/destruction of subclasses

Aggregations: Typically use pointer variables that point to an object that lives outside the scope of the aggregate class Can use reference values that point to an object that lives outside the scope of the aggregate class Not responsible for creating/destroying subclasses

It is worth noting that the concepts of composition and aggregation are not mutually exclusive, and can be mixed freely within the same class. It is entirely possible to write a class that is responsible for the creation/destruction of some subclasses but not others. For example, our Department class could have a name and a teacher. The name would probably be added to the department by composition, and would be created and destroyed with the department. On the other hand, the teacher would be added to the department by aggregate, and created/destroyed independently.It is also possible to create other hybrid aggregate/composition schemes, such as where a class holds independent subobjects like an aggregate, but will destroy them when the class goes out of scope like a composition.While aggregates can be extremely useful (which we will see more of in the next lesson on container classes), they are also potentially dangerous. As noted several times, aggregates are not responsible for deallocating their subobjects when they are destroyed. Consequently, if there are no other pointers or references to those subobjects when the aggregate is destroyed, those subobjects will cause a memory leak. It is up to the programmer to ensure that this does not happen. This is generally handled by ensuring other pointers or references to those subobjects exist when the aggregate is destroyed.

Container classesBY ALEX, ON DECEMBER 14TH, 2007In real life, we use containers all the time. Your breakfast cereal comes in a box, the pages in your book come inside a cover and binding, and you might store any number of items in containers in your garage. Without containers, it would be extremely inconvenient to work with many of these objects. Imagine trying to read a book that didn’t have any sort of binding, or eat cereal that didn’t come in a box without using a bowl. It would be a mess. The value the container provides is largely in it’s ability to help organize and store items that are put inside it.Similarly, a container class is a class designed to hold and organize multiple instances of another class. There are many different kinds of container classes, each of which has various advantages, disadvantages, and restrictions in their use. By far the most commonly used container in programming is the array, which you have already seen many examples of. Although C++ has built-in array functionality, programmers will often use an array container class instead because of the additional benefits it provides. Unlike built-in arrays, array container classes generally provide dynamically resizing (when elements are added or removed) and do bounds-checking. This not only makes array container classes more convenient than normal arrays, but safer too.Container classes typically implement a fairly standardized minimal set of functionality. Most well-defined containers will include functions that:

Create an empty container (via a constructor) Insert a new object into the container Remove an object from the container Report the number of objects currently in the container Empty the container of all objects Provide access to the stored objects Sort the elements (optional)

Sometimes certain container classes will omit some of this functionality. For example, arrays container classes often omit the insert and delete functions because they are slow and the class designer does not want to encourage their use.Container classes generally come in two different varieties. Value containers are compositions that store copies of the objects that they are holding (and thus are responsible for creating and destroying those copies). Reference containers areaggregations that store pointers or references to other objects (and thus are not responsible for creation or destruction of those objects).Unlike in real life, where containers can hold whatever you put in them, in C++, containers typically only hold one type of data. For example, if you have an array of integers, it will only hold integers. Unlike some other languages, C++ generally does not allow you to mix types inside a container. If you want one container class that holds integers and another that holds doubles, you will have to write two separate containers to do this (or use templates, which is an advanced C++ feature). Despite the restrictions on their use, containers are immensely useful, and they make programming easier, safer, and faster

#ifndef INTARRAY_H#define INTARRAY_H

#include <assert.h> // for assert()

class IntArray{private: int m_nLength;

Page 9: c++

int *m_pnData;

public: IntArray() { m_nLength = 0; m_pnData = 0; }

IntArray(int nLength) { m_pnData = new int[nLength]; m_nLength = nLength; }

~IntArray() { delete[] m_pnData; }

void Erase() { delete[] m_pnData; // We need to make sure we set m_pnData to 0 here, otherwise it will // be left pointing at deallocated memory! m_pnData = 0; m_nLength = 0; }

int& operator[](int nIndex) { assert(nIndex >= 0 && nIndex < m_nLength); return m_pnData[nIndex]; }

// Reallocate resizes the array. Any existing elements will be destroyed. // This function operates quickly. void Reallocate(int nNewLength) { // First we delete any existing elements Erase();

// If our array is going to be empty now, return here if (nNewLength<= 0) return;

// Then we have to allocate new elements m_pnData = new int[nNewLength]; m_nLength = nNewLength; }

// Resize resizes the array. Any existing elements will be kept. // This function operates slowly. void Resize(int nNewLength) { // If we are resizing to an empty array, do that and return if (nNewLength <= 0) { Erase(); return; }

// Now we can assume nNewLength is at least 1 element. This algorithm // works as follows: First we are going to allocate a new array. Then we // are going to copy elements from the existing array to the new array. // Once that is done, we can destroy the old array, and make m_pnData // point to the new array.

// First we have to allocate a new array int *pnData = new int[nNewLength];

// Then we have to figure out how many elements to copy from the existing // array to the new array. We want to copy as many elements as there are // in the smaller of the two arrays.

Page 10: c++

if (m_nLength > 0) { int nElementsToCopy = (nNewLength > m_nLength) ? m_nLength : nNewLength;

// Now copy the elements one by one for (int nIndex=0; nIndex < nElementsToCopy; nIndex++) pnData[nIndex] = m_pnData[nIndex]; }

// Now we can delete the old array because we don't need it any more delete[] m_pnData;

// And use the new array instead! Note that this simply makes m_pnData point // to the same address as the new array we dynamically allocated. Because // pnData was dynamically allocated, it won't be destroyed when it goes out of scope. m_pnData = pnData; m_nLength = nNewLength; }

void InsertBefore(int nValue, int nIndex) { // Sanity check our nIndex value assert(nIndex >= 0 && nIndex <= m_nLength);

// First create a new array one element larger than the old array int *pnData = new int[m_nLength+1];

// Copy all of the elements up to the index for (int nBefore=0; nBefore < nIndex; nBefore++) pnData[nBefore] = m_pnData[nBefore];

// insert our new element into the new array pnData[nIndex] = nValue;

// Copy all of the values after the inserted element for (int nAfter=nIndex; nAfter < m_nLength; nAfter++) pnData[nAfter+1] = m_pnData[nAfter];

// Finally, delete the old array, and use the new array instead delete[] m_pnData; m_pnData = pnData; m_nLength += 1; }

void Remove(int nIndex) { // Sanity check our nIndex value assert(nIndex >= 0 && nIndex < m_nLength);

// First create a new array one element smaller than the old array int *pnData = new int[m_nLength-1];

// Copy all of the elements up to the index for (int nBefore=0; nBefore < nIndex; nBefore++) pnData[nBefore] = m_pnData[nBefore];

// Copy all of the values after the inserted element for (int nAfter=nIndex+1; nAfter < m_nLength; nAfter++) pnData[nAfter-1] = m_pnData[nAfter];

// Finally, delete the old array, and use the new array instead delete[] m_pnData; m_pnData = pnData; m_nLength -= 1; }

// A couple of additional functions just for convenience void InsertAtBeginning(int nValue) { InsertBefore(nValue, 0); } void InsertAtEnd(int nValue) { InsertBefore(nValue, m_nLength); }

int GetLength() { return m_nLength; }};

#endif

Page 11: c++

C++ Templates Tutorial C++ Library  

  

Table of Contents

Introduction

Class Templates

Implementing a class template Implementing class template members Using a class template

Function Templates

Implementing Template Functions Using Template Functions

Template Instantiation

Class Template Specialization

Template Class Partial Specialization

Template Function Specialization

Template Parameters

Static Members and Variables

Templates and Friends

Introduction

Many C++ programs use common data structures like stacks, queues and lists. A program may require a queue of customers and a queue of messages. One could easily implement a queue of customers, then take the existing code and implement a queue of messages. The program grows, and now there is a need for a queue of orders. So just take the queue of messages and convert that to a queue of orders (Copy, paste, find, replace????). Need to make some changes to the queue implementation? Not a very easy task, since the code has been duplicated in many places. Re-inventing source code is not an intelligent approach in an object oriented environment which encourages re-usability. It seems to make more sense to implement a queue that can contain any arbitrary type rather than duplicating code. How does one do that? The answer is to use type parameterization, more commonly referred to as templates.

Page 12: c++

C++ templates allow one to implement a generic Queue<T> template that has a type parameter T. T can be replaced with actual types, for example, Queue<Customers>, and C++ will generate the class Queue<Customers>. Changing the implementation of the Queue becomes relatively simple. Once the changes are implemented in the template Queue<T>, they are immediately reflected in the classes Queue<Customers>, Queue<Messages>, and Queue<Orders>.

Templates are very useful when implementing generic constructs like vectors, stacks, lists, queues which can be used with any arbitrary type. C++ templates provide a way to re-use source code as opposed to inheritance and composition which provide a way to re-use object code.

C++ provides two kinds of templates: class templates and function templates. Use function templates to write generic functions that can be used with arbitrary types. For example, one can write searching and sorting routines which can be used with any arbitrary type. The Standard Template Library generic algorithms have been implemented as function templates, and the containers have been implemented as class templates.

Class Templates

Implementing a class template

A class template definition looks like a regular class definition, except it is prefixed by the keyword template. For example, here is the definition of a class template for a Stack.

template <class T>class Stack{public:

Stack(int = 10) ; ~Stack() { delete [] stackPtr ; }int push(const T&); int pop(T&) ; int isEmpty()const { return top == -1 ; } int isFull() const { return top == size - 1 ; }

private:int size ; // number of elements on Stack.int top ; T* stackPtr ;

} ;

T is a type parameter and it can be any type. For example, Stack<Token>, where Token is a user defined class. T does not have to be a class type as implied by the keyword class. For example, Stack<int> and Stack<Message*> are valid instantiations, even though int and Message* are not "classes".

Implementing class template member functions

Implementing template member functions is somewhat different compared to the regular class member functions. The declarations and definitions of the class template member functions should all be in the same header file. The declarations and definitions need to be in the same header file. Consider the following. 

//B.Htemplate <class t>class b{public:

// B.CPP#include "B.H"template <class t>b<t>::b(){

//MAIN.CPP#include "B.H"void main(){

b<int> bi ;

Page 13: c++

b() ;~b() ;

} ;

}template <class t>b<t>::~b(){}

b <float> bf ;}

When compiling B.cpp, the compiler has both the declarations and the definitions available. At this point the compiler does not need to generate any definitions for template classes, since there are no instantiations. When the compiler compiles main.cpp, there are two instantiations: template class B<int> and B<float>. At this point the compiler has the declarations but no definitions!

While implementing class template member functions, the definitions are prefixed by the keyword template. Here is the complete implementation of class template Stack:

//stack.h#pragma oncetemplate <class T>class Stack{public:

Stack(int = 10) ; ~Stack() { delete [] stackPtr ; }int push(const T&); int pop(T&) ; // pop an element off the stackint isEmpty()const { return top == -1 ; } int isFull() const { return top == size - 1 ; }

private:int size ; // Number of elements on Stackint top ; T* stackPtr ;

} ;

//constructor with the default size 10template <class T>Stack<T>::Stack(int s){

size = s > 0 && s < 1000 ? s : 10 ; top = -1 ; // initialize stackstackPtr = new T[size] ;

} // push an element onto the Stack template <class T>int Stack<T>::push(const T& item){

if (!isFull()){

stackPtr[++top] = item ;return 1 ; // push successful

}return 0 ; // push unsuccessful

}

// pop an element off the Stacktemplate <class T> int Stack<T>::pop(T& popValue) {

if (!isEmpty()){

popValue = stackPtr[top--] ;return 1 ; // pop successful

}

Page 14: c++

return 0 ; // pop unsuccessful}

Using a class template

Using a class template is easy. Create the required classes by plugging in the actual type for the type parameters. This process is commonly known as "Instantiating a class". Here is a sample driver class that uses the Stack class template.

#include <iostream>#include "stack.h"using namespace std ;void main(){

typedef Stack<float> FloatStack ;typedef Stack<int> IntStack ;

FloatStack fs(5) ;float f = 1.1 ;cout << "Pushing elements onto fs" << endl ;while (fs.push(f)){

cout << f << ' ' ;f += 1.1 ;

}cout << endl << "Stack Full." << endl<< endl << "Popping elements from fs" << endl ;while (fs.pop(f))

cout << f << ' ' ;cout << endl << "Stack Empty" << endl ;cout << endl ;

IntStack is ;int i = 1.1 ;cout << "Pushing elements onto is" << endl ;while (is.push(i)){

cout << i << ' ' ;i += 1 ;

}cout << endl << "Stack Full" << endl<< endl << "Popping elements from is" << endl ;while (is.pop(i))

cout << i << ' ' ;cout << endl << "Stack Empty" << endl ;

}

Program OutputPushing elements onto fs1.1 2.2 3.3 4.4 5.5 Stack Full.

Popping elements from fs5.5 4.4 3.3 2.2 1.1 Stack Empty

Pushing elements onto is1 2 3 4 5 6 7 8 9 10 Stack Full

Popping elements from is

Page 15: c++

10 9 8 7 6 5 4 3 2 1 Stack Empty

In the above example we defined a class template Stack. In the driver program we instantiated a Stack of float (FloatStack) and a Stack of int(IntStack). Once the template classes are instantiated you can instantiate objects of that type (for example, fs and is.)

A good programming practice is using typedef while instantiating template classes. Then throughout the program, one can use the typedef name. There are two advantages:

typedef's are very useful when "templates of templates" come into usage. For example, when instantiating an STL vector of int's, you could use:

typedef vector<int, allocator<int> > INTVECTOR ;

If the template definition changes, simply change the typedef definition. For example, currently the definition of template class vector requires a second parameter.

typedef vector<int, allocator<int> > INTVECTOR ; INTVECTOR vi1 ;

In a future version, the second parameter may not be required, for example,

typedef vector<int> INTVECTOR ;INTVECTOR vi1 ;

Imagine how many changes would be required if there was no typedef!

Function Templates

To perform identical operations for each type of data compactly and conveniently, use function templates. You can write a single function template definition. Based on the argument types provided in calls to the function, the compiler automatically instantiates separate object code functions to handle each type of call appropriately. The STL algorithms are implemented as function templates.

Implementing Template Functions

Function templates are implemented like regular functions, except they are prefixed with the keyword template. Here is a sample with a function template.

#include <iostream>using namespace std ;//max returns the maximum of the two elementstemplate <class T>T max(T a, T b){

return a > b ? a : b ;}

Using Template Functions

Using function templates is very easy: just use them like regular functions. When the compiler sees an instantiation of the function template, for example: the call max(10, 15) in function main, the compiler generates a function max(int, int). Similarly the compiler generates definitions for max(char, char) and max(float, float) in this case.

Page 16: c++

#include <iostream>using namespace std ;//max returns the maximum of the two elementstemplate <class T>T max(T a, T b){

return a > b ? a : b ;}void main(){

cout << "max(10, 15) = " << max(10, 15) << endl ;cout << "max('k', 's') = " << max('k', 's') << endl ;cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;

}

Program Outputmax(10, 15) = 15max('k', 's') = smax(10.1, 15.2) = 15.2

Template Instantiation

When the compiler generates a class, function or static data members from a template, it is referred to as template instantiation.

A class generated from a class template is called a generated class.

A function generated from a function template is called a generated function.

A static data member generated from a static data member template is called a generated static data member.

The compiler generates a class, function or static data members from a template when it sees an implicit instantiation or an explicit instantiation of the template.

1. Consider the following sample. This is an example of implicit instantiation of a class template.2. template <class T>3. class Z4. {5. public:6. Z() {} ;7. ~Z() {} ;8. void f(){} ;9. void g(){} ;10. } ;11.12. int main()13. {14. Z<int> zi ; //implicit instantiation generates class Z<int>15. Z<float> zf ; //implicit instantiation generates class Z<float>16. return 0 ;17. }18. Consider the following sample. This sample uses the template class members Z<T>::f() and Z<T>::g().19. template <class T>20. class Z21. {22. public:23. Z() {} ;24. ~Z() {} ;25. void f(){} ;26. void g(){} ;27. } ;

Page 17: c++

28.29. int main()30. {31. Z<int> zi ; //implicit instantiation generates class Z<int>32. zi.f() ; //and generates function Z<int>::f()33. Z<float> zf ; //implicit instantiation generates class Z<float>34. zf.g() ; //and generates function Z<float>::g()35. return 0 ;36. }

This time in addition to the generating classes Z<int> and Z<float>, with constructors and destructors, the compiler also generates definitions for Z<int>::f() and Z<float>::g(). The compiler does not generate definitions for functions, nonvirtual member functions, class or member class that does not require instantiation. In this example, the compiler did not generate any definitions for Z<int>::g() and Z<float>::f(), since they were not required.

37. Consider the following sample. This is an example of explicit instantiation of a class template.38. template <class T>39. class Z40. {41. public:42. Z() {} ;43. ~Z() {} ;44. void f(){} ;45. void g(){} ;46. } ;47.48. int main()49. {50. template class Z<int> ; //explicit instantiation of class Z<int>51. template class Z<float> ; //explicit instantiation of 52. //class Z<float>53. return 0 ;54. }55. Consider the following sample. Will the compiler generate any classes in this case? The answer is NO.56. template <class T>57. class Z58. {59. public:60. Z() {} ;61. ~Z() {} ;62. void f(){} ;63. void g(){} ;64. } ;65.66. int main()67. {68. Z<int>* p_zi ; //instantiation of class Z<int> not required69. Z<float>* p_zf ; //instantiation of class Z<float> not required70. return 0 ;71. }

This time the compiler does not generate any definitions! There is no need for any definitions. It is similar to declaring a pointer to an undefined class or struct.

72. Consider the following sample. This is an example of implicit instantiation of a function template.73. //max returns the maximum of the two elements74. template <class T>75. T max(T a, T b)76. {77. return a > b ? a : b ;78. }

Page 18: c++

79. void main()80. {81. int I ;82. I = max(10, 15) ; //implicit instantiation of max(int, int)83. char c ;84. c = max('k', 's') ; //implicit instantiation of max(char, char)85. }

In this case the compiler generates functions max(int, int) and max(char, char). The compiler generates definitions using the template function max.

86. Consider the following sample. This is an example of explicit instantiation of a function template.87. template <class T>88. void Test(T r_t)89. {90. }91.92. int main()93. {94. //explicit instantiation of Test(int)95. template void Test<int>(int) ;96. return 0 ;97. }

NOTE: Visual C++ 5.0 does not support this syntax currently. The above sample causes compiler error C1001.

In this case the compiler would generate function Test(int). The compiler generates the definition using the template function Test.

98. If an instantiation of a class template is required, and the template declared but not defined, the program is ill-formed. VC5.0 compiler generates error C2079.

99. template <class T> class X ;100.101. int main()102. {103. X<int> xi ; //error C2079: 'xi' uses undefined class 'X<int>'104. return 0 ;105. }106. Instantiating virtual member functions of a class template that does not require instantiation is implementation defined.

For example, in the following sample, virtual function X<T>::Test() is not required, VC5.0 generates a definition for X<T>::Test.

107. template <class T> 108. class X 109. {110. public:111. virtual void Test() {} 112. };113.114. int main()115. {116. X<int> xi ; //implicit instantiation of X<int>117. return 0 ;118. }

In this case the compiler generates a definition for X<int>::Test, even if it is not required.

Class Template Specialization

Page 19: c++

In some cases it is possible to override the template-generated code by providing special definitions for specific types. This is called template specialization. The following example defines a template class specialization for template class stream.

#include <iostream>using namespace std ;

template <class T>class stream{

public:void f() { cout << "stream<T>::f()"<< endl ;}

} ;

template <>class stream<char>{

public:void f() { cout << "stream<char>::f()"<< endl ;}

} ;

int main(){

stream<int> si ;stream<char> sc ;

si.f() ;sc.f() ;

return 0 ;}

Program Outputstream<T>::f()stream<char>::f()

In the above example, stream<char> is used as the definition of streams of chars; other streams will be handled by the template class generated from the class template.

Template Class Partial Specialization

You may want to generate a specialization of the class for just one parameter, for example

//base template classtemplate<typename T1, typename T2> class X {} ;

//partial specializationtemplate<typename T1> class X<T1, int> {} ; //C2989 here

int main(){

// generates an instantiation from the base templateX<char, char> xcc ;

Page 20: c++

//generates an instantiation from the partial specializationX<char, int> xii ;

return 0 ;}

A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list.

NOTE: Visual C++ 5.0 does not support template class partial specialization. The above sample causes compiler error C2989: template class has already been defined as a non-template class.

Template Function Specialization

In some cases it is possible to override the template-generated code by providing special definitions for specific types. This is called template specialization. The following example demonstrates a situation where overriding the template generated code would be necessary:

#include <iostream>using namespace std ;

//max returns the maximum of the two elements of type T, where T is a//class or data type for which operator> is defined.template <class T>T max(T a, T b){ return a > b ? a : b ;}

int main(){ cout << "max(10, 15) = " << max(10, 15) << endl ; cout << "max('k', 's') = " << max('k', 's') << endl ; cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ; cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin", "Jasmine") << endl ; return 0 ;}

Program Outputmax(10, 15) = 15max('k', 's') = smax(10.1, 15.2) = 15.2max("Aladdin", "Jasmine") = Aladdin

Not quite the expected results! Why did that happen? The function call max("Aladdin", "Jasmine") causes the compiler to generate code for max(char*, char*), which compares the addresses of the strings! To correct special cases like these or to provide more efficient implementations for certain types, one can use template specializations. The above example can be rewritten with specialization as follows:

#include <iostream>#include <cstring>using namespace std ;

//max returns the maximum of the two elementstemplate <class T>T max(T a, T b){ return a > b ? a : b ;

Page 21: c++

}

// Specialization of max for char*template <>char* max(char* a, char* b){ return strcmp(a, b) > 0 ? a : b ;}

int main(){ cout << "max(10, 15) = " << max(10, 15) << endl ; cout << "max('k', 's') = " << max('k', 's') << endl ; cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ; cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin", "Jasmine") << endl ; return 0 ;}

Program Outputmax(10, 15) = 15max('k', 's') = smax(10.1, 15.2) = 15.2max("Aladdin", "Jasmine") = Jasmine

Template Parameters

1. C++ templates allow one to implement a generic Queue<T> template that has a type parameter T. T can be replaced with actual types, for example, Queue<Customers>, and C++ will generate the class Queue<Customers>. For example,

2. template <class T>3. class Stack4. {5. } ;

Here T is a template parameter, also referred to as type-parameter.

6. C++ allows you to specify a default template parameter, so the definition could now look like:7. template <class T = float, int elements = 100> Stack { ....} ;

Then a declaration such as

Stack<> mostRecentSalesFigures ;

would instantiate (at compile time) a 100 element Stack template class named mostRecentSalesFigures of float values; this template class would be of type Stack<float, 100>.

Note, C++ also allows non-type template parameters. In this case, template class Stack has an int as a non-type parameter.

If you specify a default template parameter for any formal parameter, the rules are the same as for functions and default parameters. Once a default parameter is declared all subsequent parameters must have defaults.

8. Default arguments cannot be specified in a declaration or a definition of a specialization. For example,9. template <class T, int size>10. class Stack11. {12. } ;

Page 22: c++

13.14. //error C2989: 'Stack<int,10>' : template class has already been15. //defined as a non-template class16. template <class T, int size = 10>17. class Stack<int, 10>18. {19. } ;20.21. int main()22. {23. Stack<float,10> si ;24. return 0 ;25. }26. A type-parameter defines its identifier to be a type-name in the scope of the template declaration, and canot be re-

declared within its scope (including nested scopes). For example,27. template <class T, int size>28. class Stack29. {30. int T ; //error type-parameter re-defined.31. void f()32. {33. char T ; //error type-parameter re-defined.34. }35. } ;36.37. class A {} ;38. int main()39. {40. Stack<A,10> si ;41. return 0 ;42. }

NOTE: VC++ 5.0 or SP1 compiles this sample without any errors. It does not flag the re-definition of type-parameter as an error.

43. The value of a non-type-parameter cannot be assigned to or have its value changed. For example,44. template <class T, int size>45. class Stack46. {47. void f()48. {49. //error C2105: '++' needs l-value 50. size++ ; //error change of template argument value51. }52. } ;53.54.55. int main()56. {57. Stack<double,10> si ;58. return 0 ;59. }60. A template-parameter that could be interpreted as either a parameter-declaration or a type-parameter, is taken as a type-

parameter. For example,61. class T {} ;62. int i ;63.64. template <class T, T i>65. void f(T t)66. {67. T t1 = i ; //template arguments T and i68. ::T t2 = ::i ; //globals T and i 69. }

Page 23: c++

70.71.72.73. int main()74. {75. f('s') ; //C2783 here76. return 0 ;77. }

NOTE: Compiling the above sample using VC++ 5.0 and SP1 causes compiler error C2783: could not deduce template argument for 'i'. To workaround the problem, replace the call to f('s') with f<char, 's'>('s').

class T {} ;int i ;

template <class T, T i>void f(T t){T t1 = i ; //template arguments T and i::T t2 = ::i ; //globals T and i

}

int main(){f<char, 's'>('s') ; //workaroundreturn 0 ;

}

78. A non-type template parameter cannot be of floating type. For example,79. template <double d> class X ; //error C2079: 'xd' uses 80. //undefined class 'X<1.e66>'81. //template <double* pd> class X ; //ok82. //template <double& rd> class X ; //ok83.84. int main()85. {86. X<1.0> xd ;87. return 0 ;88. }

Static Members and Variables

1. Each template class or function generated from a template has its own copies of any static variables or members.2. Each instantiation of a function template has it's own copy of any static variables defined within the scope of the function.

For example,3. template <class T>4. class X5. {6. public:7. static T s ;8. } ;9.10. int main()11. {12. X<int> xi ;13. X<char*> xc ;14. }

Here X<int> has a static data member s of type int and X<char*> has a static data member s of type char*.

Page 24: c++

15. Static members are defined as follows.16. #include <iostream>17. using namespace std ;18.19. template <class T>20. class X21. {22. public:23. static T s ;24. } ;25.26. template <class T> T X<T>::s = 0 ;27. template <> int X<int>::s = 3 ;28. template <> char* X<char*>::s = "Hello" ;29.30. int main()31. {32. X<int> xi ;33. cout << "xi.s = " << xi.s << endl ;34.35. X<char*> xc ;36. cout << "xc.s = " << xc.s << endl ;37.38. return 0 ;39. }

Program Outputxi.s = 10xc.s = Hello

40. Each instantiation of a function template has it's own copy of the static variable. For example,41. #include <iostream>42. using namespace std ;43.44. template <class T>45. void f(T t)46. {47. static T s = 0;48. s = t ;49. cout << "s = " << s << endl ;50. } 51.52. int main()53. {54. f(10) ;55. f("Hello") ;56.57. return 0 ;58. }

Program Outputs = 10s = Hello

Here f<int>(int) has a static variable s of type int, and f<char*>(char*) has a static variable s of type char*.

Templates and Friends

Page 25: c++

Friendship can be established between a class template and a global function, a member function of another class (possibly a template class), or even an entire class (possible template class). The table below lists the results of declaring different kinds of friends of a class.

Class Template friend declaration in class template X Results of giving friendship

template class <T> class X

friend void f1() ;makes f1() a friend of all instantiations of template X. For example, f1() is a friend of X<int>, X<A>, and X<Y>.

template class <T> class X

friend void f2(X<T>&) ;For a particular type T for example, float, makes f2(X<float>&) a friend of class X<float> only. f2(x<float>&) cannot be a friend of class X<A>.

template class <T> class X

friend A::f4() ; // A is a user defined class with a member function f4() ;

makes A::f4() a friend of all instantiations of template X. For example, A::f4() is a friend of X<int>, X<A>, and X<Y>.

template class <T> class X

friend C<T>::f5(X<T>&) ; // C is a class template with a member function f5

For a particular type T for example, float, makes C<float>::f5(X<float>&) a friend of class X<float> only. C<float>::f5(x<float>&) cannot be a friend of class X<A>.

template class <T> class X

friend class Y ;makes every member function of class Y a friend of every template class produced from the class template X.

template class <T> class X

friend class Z<T> ;when a template class is instantiated with a particular type T, such as a float, all members of class Z<float> become friends of template class X<float>.

© 1997 Microsoft Corporation. All rights reserved. Terms of Use.

To #include a standard header file (such as <cstdio>), you don't have to do anything unusual. E.g.

 // This is C++ code  #include <cstdio>                // Nothing unusual in #include line  int main() {   std::printf("Hello world\n");  // Nothing unusual in the call either   ... }

How can I include a non-system C header file in my C++ code?// This is C++ code  extern "C" {   // Get declaration for f(int i, char c, float x)   #include "my-C-code.h"

Page 26: c++

 }  int main() {   f(7, 'x', 3.14);   // Note: nothing unusual in the call   ... }

How can I modify my own C header files so it's easier to #include them in C++ code

If you are including a C header file that isn't provided by the system, and if you are able to change the C header, you should strongly consider adding the extern "C" {...} logic inside the header to make it easier for C++ users to #include it into their C++ code. Since a C compiler won't understand the extern "C" construct, you must wrap the extern "C" { and } lines in an #ifdef so they won't be seen by normal C compilers.

Step #1: Put the following lines at the very top of your C header file (note: the symbol __cplusplus is #defined if/only-if the compiler is a C++ compiler):

 #ifdef __cplusplus extern "C" { #endif

Step #2: Put the following lines at the very bottom of your C header file:

 #ifdef __cplusplus } #endif

Now you can #include your C header without any extern "C" nonsense in your C++ code:

 // This is C++ code 

 // Get declaration for f(int i, char c, float x) #include "my-C-code.h"   // Note: nothing unusual in #include line  int main() {

   f(7, 'x', 3.14);       // Note: nothing unusual in the call   ... }

How can I call a non-system C function f(int,char,float) from my C++ code?

Page 27: c++

If you have an individual C function that you want to call, and for some reason you don't have or don't want to #include a C header file in which that function is declared, you can declare the individual C function in your C++ code using the extern "C" syntax. Naturally you need to use the full function prototype:

 extern "C" void f(int i, char c, float x);

A block of several C functions can be grouped via braces:

 extern "C" {   void   f(int i, char c, float x);   int    g(char* s, char const* s2);   double sqrtOfSumOfSquares(double a, double b); }

After this you simply call the function just as if it were a C++ function:

 int main() {

   f(7, 'x', 3.14);   // Note: nothing unusual in the call   ... }

How can I create a C++ function f(int,char,float) that is callable by my C code?

The C++ compiler must know that f(int,char,float) is to be called by a C compiler using the extern "C"   construct :

 // This is C++ code 

 // Declare f(int,char,float) using extern "C": extern "C" void f(int i, char c, float x); 

 ... 

 // Define f(int,char,float) in some C++ module: void f(int i, char c, float x) {

   ... }

The extern "C" line tells the compiler that the external information sent to the linker should use C calling conventions and name mangling (e.g., preceded by

Page 28: c++

a single underscore). Since name overloading isn't supported by C, you can't make several overloaded functions simultaneously callable by a C program.

How can I pass an object of a C++ class to/from a C function?  UPDATED! 

[Recently rewrote prose to clarify issues surrounding different binary representations for Base* and Derived* (in 8/10). Click here to go to the next FAQ in the "chain" of recent changes.]

Here's an example (for info on extern "C", see the previous two FAQs).

Fred.h:

 /* This header can be read by both C and C++ compilers */ #ifndef FRED_H #define FRED_H  #ifdef __cplusplus   class Fred {   public:     Fred();     void wilma(int);   private:     int a_;   }; #else   typedef     struct Fred       Fred; #endif  #ifdef __cplusplus extern "C" { #endif  #if defined(__STDC__) || defined(__cplusplus)

   extern void c_function(Fred*);   /* ANSI C prototypes */   extern Fred* cplusplus_callback_function(Fred*); #else

   extern void c_function();        /* K&R style */   extern Fred* cplusplus_callback_function(); #endif  #ifdef __cplusplus } #endif

Page 29: c++

 

 #endif /*FRED_H*/

Fred.cpp:

 // This is C++ code  #include "Fred.h"  Fred::Fred() : a_(0) { }  void Fred::wilma(int a) { }  Fred* cplusplus_callback_function(Fred* fred) {   fred->wilma(123);   return fred; }

main.cpp:

 // This is C++ code  #include "Fred.h"  int main() {   Fred fred;   c_function(&fred);

   ... }

c-function.c:

 /* This is C code */  #include "Fred.h"  void c_function(Fred* fred) {   cplusplus_callback_function(fred); }

Unlike your C++ code, your C code will not be able to tell that two pointers point at the same object unless the pointers are exactly the same type. For example, in C++ it is easy to check if aDerived* called dp points to the same

Page 30: c++

object as is pointed to by a Base* called bp: just say if (dp == bp) .... The C++ compiler automatically converts both pointers to the same type, in this case to Base*, then compares them. Depending on the C++ compiler's implementation details, this conversion sometimes changes the bits of a pointer's value.

(Technical aside: Most C++ compilers use a binary object layout that causes this conversion to happen with multiple inheritance and/or virtual inheritance. However the C++ language does not impose that object layout so in principle a conversion could also happen even with non-virtual single inheritance.)

The point is simple: your C compiler will not know how to do that pointer conversion, so the conversion from Derived* to Base*, for example, must take place in code compiled with a C++ compiler, not in code compiled with a C compiler.

NOTE: you must be especially careful when converting both to void* since that conversion will not allow either the C or C++ compiler to do the proper pointer adjustments! The comparison(x == y) might be false even if (b == d) is true:

 void f(Base* b, Derived* d) {

   if (b == d) {   <img src="smile.gif" alt="good"> Validly compares a Base* to a Derived*</img src="smile.gif" alt="good">

     ...   }    void* x = b;   void* y = d;

   if (x == y) {   <img src="frown.gif" alt="bad"> BAD FORM! DO NOT DO THIS!</img src="frown.gif" alt="bad">     ...   } }

As stated above, the above pointer conversions will typically happen with multiple and/or virtual inheritance, but please do not look at that as an exhaustive list of the only times when the pointer conversions will happen.

You have been warned.

If you really want to use void* pointers, here is the safe way to do it:

Page 31: c++

 void f(Base* b, Derived* d) {   void* x = b;

   void* y = static_cast<Base*>(d);  ← If conversion is needed, it will happen in the static_cast<>   if (x == y) {   <img src="smile.gif" alt="good"> Validly compares a Base* to a Derived*</img src="smile.gif" alt="good">

     ...   } }

What is a copy constructor?A copy constructor is a special constructor for a class/struct that isused to make a copy of an existing instance. According to the C++standard, the copy constructor for MyClass must have one of thefollowing signatures:

1234

MyClass( const MyClass& other ); MyClass( MyClass& other ); MyClass( volatile const MyClass& other ); MyClass( volatile MyClass& other );

Note that none of the following constructors, despite the fact thatthey could do the same thing as a copy constructor, are copyconstructors:

12 MyClass( MyClass* other ); MyClass( const MyClass* other );

or my personal favorite way to create an infinite loop in C++:

  MyClass( MyClass other );

When do I need to write a copy constructor?First, you should understand that if you do not declare a copyconstructor, the compiler gives you one implicitly. The implicitcopy constructor does a member-wise copy of the source object.For example, given the class:

Page 32: c++

12345

class MyClass { int x; char c; std::string s; };

the compiler-provided copy constructor is exactly equivalent to:

123

MyClass::MyClass( const MyClass& other ) : x( other.x ), c( other.c ), s( other.s ) {}

In many cases, this is sufficient. However, there are certaincircumstances where the member-wise copy version is not good enough.By far, the most common reason the default copy constructor is notsufficient is because the object contains raw pointers and you needto take a "deep" copy of the pointer. That is, you don't want to copy the pointer itself; rather you want to copy what the pointerpoints to. Why do you need to take "deep" copies? This is typically because the instance owns the pointer; that is, theinstance is responsible for calling delete on the pointer at somepoint (probably the destructor). If two objects end up callingdelete on the same non-NULL pointer, heap corruption results.

Rarely you will come across a class that does not contain rawpointers yet the default copy constructor is not sufficient.An example of this is when you have a reference-counted object.boost::shared_ptr<> is example.

Const correctnessWhen passing parameters by reference to functions or constructors, be verycareful about const correctness. Pass by non-const reference ONLY ifthe function will modify the parameter and it is the intent to changethe caller's copy of the data, otherwise pass by const reference.

Why is this so important? There is a small clause in the C++ standardthat says that non-const references cannot bind to temporary objects.A temporary object is an instance of an object that does not have avariable name. For example:

  std::string( "Hello world" );

is a temporary, because we have not given it a variable name. Thisis not a temporary:

  std::string s( "Hello world" );

because the object's name is s.

What is the practical implication of all this? Consider the following:

12 // Improperly declared function: parameter should be const reference: void print_me_bad( std::string& s ) {

Page 33: c++

34567891011121314151617181920

std::cout << s << std::endl; }

// Properly declared function: function has no intent to modify s: void print_me_good( const std::string& s ) { std::cout << s << std::endl; }

std::string hello( "Hello" );

print_me_bad( hello ); // Compiles ok; hello is not a temporary print_me_bad( std::string( "World" ) ); // Compile error; temporary object print_me_bad( "!" ); // Compile error; compiler wants to construct temporary // std::string from const char*

print_me_good( hello ); // Compiles ok print_me_good( std::string( "World" ) ); // Compiles ok print_me_good( "!" ); // Compiles ok

Many of the STL containers and algorithms require that an objectbe copyable. Typically, this means that you need to have thecopy constructor that takes a const reference, for the abovereasons.

What is an assignment operator?The assignment operator for a class is what allows you to use= to assign one instance to another. For example:

12 MyClass c1, c2; c1 = c2; // assigns c2 to c1

There are actually several different signatures that anassignment operator can have:

(1) MyClass& operator=( const MyClass& rhs );(2) MyClass& operator=( MyClass& rhs );(3) MyClass& operator=( MyClass rhs );(4) const MyClass& operator=( const MyClass& rhs );(5) const MyClass& operator=( MyClass& rhs );(6) const MyClass& operator=( MyClass rhs );(7) MyClass operator=( const MyClass& rhs );(8) MyClass operator=( MyClass& rhs );(9) MyClass operator=( MyClass rhs );

These signatures permute both the return type and the parametertype. While the return type may not be too important, choiceof the parameter type is critical.

(2), (5), and (8) pass the right-hand side by non-const reference,and is not recommended. The problem with these signatures is thatthe following code would not compile:

12 MyClass c1; c1 = MyClass( 5, 'a', "Hello World" ); // assuming this constructor

Page 34: c++

exists

This is because the right-hand side of this assignment expression isa temporary (un-named) object, and the C++ standard forbids the compilerto pass a temporary object through a non-const reference parameter.

This leaves us with passing the right-hand side either by value orby const reference. Although it would seem that passing by constreference is more efficient than passing by value, we will see laterthat for reasons of exception safety, making a temporary copy of thesource object is unavoidable, and therefore passing by value allowsus to write fewer lines of code.

When do I need to write an assignment operator?First, you should understand that if you do not declare anassignment operator, the compiler gives you one implicitly. Theimplicit assignment operator does member-wise assignment of each data member from the source object. For example, usingthe class above, the compiler-provided assignment operator isexactly equivalent to:

123456

MyClass& MyClass::operator=( const MyClass& rhs ) { x = other.x; c = other.c; s = other.s; return *this; }

In general, any time you need to write your own custom copy constructor, you also need to write a custom assignment operator.

What is meant by Exception Safe code?A little interlude to talk about exception safety, because programmersoften misunderstand exception handling to be exception safety.

A function which modifies some "global" state (for example, a referenceparameter, or a member function that modifies the data members of its instance) is said to be exception safe if it leaves the global statewell-defined in the event of an exception that is thrown at any pointduring the function.

What does this really mean? Well, let's take a rather contrived(and trite) example. This class wraps an array of some user-specifiedtype. It has two data members: a pointer to the array and a number of elements in the array.

123456789

template< typename T > class MyArray { size_t numElements; T* pElements;

public: size_t count() const { return numElements; } MyArray& operator=( const MyArray& rhs ); };

Page 35: c++

Now, assignment of one MyArray to another is easy, right?

1234567891011

template<> MyArray<T>::operator=( const MyArray& rhs ) { if( this != &rhs ) { delete [] pElements; pElements = new T[ rhs.numElements ]; for( size_t i = 0; i < rhs.numElements; ++i ) pElements[ i ] = rhs.pElements[ i ]; numElements = rhs.numElements; } return *this; }

Well, not so fast. The problem is, the line

  pElements[ i ] = rhs.pElements[ i ];

could throw an exception. This line invokes operator= for type T, whichcould be some user-defined type whose assignment operator might throw anexception, perhaps an out-of-memory (std::bad_alloc) exception or someother exception that the programmer of the user-defined type created.

What would happen if it did throw, say on copying the 3rd element of 10total? Well, the stack is unwound until an appropriate handler is found. Meanwhile, what is the state of our object? Well, we've reallocated ourarray to hold 10 T's, but we've copied only 2 of them successfully. Thethird one failed midway, and the remaining seven were never even attemptedto be copied. Furthermore, we haven't even changed numElements, so whateverit held before, it still holds. Clearly this instance will lie about thenumber of elements it contains if we call count() at this point.

But clearly it was never the intent of MyArray's programmer to have count()give a wrong answer. Worse yet, there could be other member functions thatrely more heavily (even to the point of crashing) on numElements being correct.Yikes -- this instance is clearly a timebomb waiting to go off.

This implementation of operator= is not exception safe: if an exception isthrown during execution of the function, there is no telling what the stateof the object is; we can only assume that it is in such a bad state (ie,it violates some of its own invariants) as to be unusable. If the object is in a bad state, it might not even be possible to destroy the object withoutcrashing the program or causing MyArray to perhaps throw another exception. And we know that the compiler runs destructors while unwinding the stack to search for a handler. If an exception is thrown while unwinding the stack,the program necessarily and unstoppably terminates.

How do I write an exception safe assignment operator?The recommended way to write an exception safe assignment operator is viathe copy-swap idiom. What is the copy-swap idiom? Simply put, it is a two-step algorithm: first make a copy, then swap with the copy. Here is ourexception safe version of operator=:

Page 36: c++

1234567891011

template<> MyArray<T>::operator=( const MyArray& rhs ) { // First, make a copy of the right-hand side MyArray tmp( rhs );

// Now, swap the data members with the temporary: std::swap( numElements, tmp.numElements ); std::swap( pElements, tmp.pElements );

return *this; }

Here's where the difference between exception handling and exception safetyis important: we haven't prevented an exception from occurring; indeed,the copy construction of tmp from rhs may throw since it will copy T's.But, if the copy construction does throw, notice how the state of *thishas not changed, meaning that in the face of an exception, we can guaranteethat *this is still coherent, and furthermore, we can even say that it isleft unchanged.

But, you say, what about std::swap? Could it not throw? Yes and no. Thedefault std::swap<>, defined in <algorithm> can throw, since std::swap<>looks like this:

1234567

template< typename T > swap( T& one, T& two ) { T tmp( one ); one = two; two = tmp; }

The first line runs the copy constructor of T, which can throw; the remaining lines are assignment operators which can also throw.

HOWEVER, if you have a type T for which the default std::swap() may resultin either T's copy constructor or assignment operator throwing, you are politely required to provide a swap() overload for your type that does notthrow. [Since swap() cannot return failure, and you are not allowed to throw,your swap() overload must always succeed.] By requiring that swap does not throw, the above operator= is thus exception safe: either the object is completely copied successfully, or the left-hand side is left unchanged.

Now you'll notice that our implementation of operator= makes a temporarycopy as its first line of code. Since we have to make a copy, we might aswell let the compiler do that for us automatically, so we can change thesignature of the function to take the right-hand side by value (ie, a copy)rather than by reference, and this allows us to eliminate one line of code:

12345

template<> MyArray<T>::operator=( MyArray tmp ) { std::swap( numElements, tmp.numElements ); std::swap( pElements, tmp.pElements ); return *this; }

Page 37: c++

6

http://www.cplusplus.com/articles/

http://www.mochima.com/tutorials/index.html