Sunday, 21 June 2015

Methods of choosing overloading vs. default arguments in C++

Methods of choosing overloading vs. default arguments in Cpp with example:

Both function overloading and default arguments provide a convenience for calling function names. However, it can seem confusing at times to know which technique to use. For example, consider the following tool that is designed to automatically manage blocks of memory for you:

#include "stdafx.h"

#include <iostream>

#include <stdio.h>

#include <cstring>

using namespace std;


//: C07:TestMemory.h

#ifndef TESTMEMORY_H

#define TESTMEMORY_H

typedef unsigned char byte;

class TestMemory {

int m_iSize;

byte* TestMemory1;

void CreateSize (int minSize);

public:

TestMemory ();  // constructor of the class

TestMemory (int sz); // parameterized constructor of the class

~TestMemory (); // destructor of the class

int FindSize ();  //  Find the size

byte* pointer ();  // get the pointer

byte* pointer (int minSize);   // return the pointer

};

#endif // TESTMEMORY_H ///:~

A TestMemory object holds a block of bytes and makes sure that you have enough storage. AS we know that the default constructor doesn’t allocate any storage, and the parameterized constructor ensures that there is sz storage in the TestMemory object.
The destructor releases the storage, msize( ) tells you how many bytes there are currently in the TestMemory object, and pointer( ) produces a pointer to the starting address of the storage.
 Let us see the full class implementation regarding the memory allocation
#include "stdafx.h"

#include <iostream>

#include <stdio.h>

#include <cstring>

using namespace std;

//: C07:TestMemory.h

#ifndef TESTMEMORY_H

#define TESTMEMORY_H

typedef unsigned char byte;

class TestMemory {

int m_iSize;

byte* TestMemory1;

void CreateSize (int minSize);

public:

TestMemory ();  // constructor of the class

TestMemory (int sz);  // parameterized constructor of the class

~TestMemory (); // destructor of the class

int FindSize ();  //  Find the size

byte* pointer ();  // get the pointer

byte* pointer (int minSize);   // return the pointer

};

#endif // TESTMEMORY_H ///:~

TestMemory::TestMemory ()

  {   TestMemory1 = NULL; m_iSize = 0; }

TestMemory::TestMemory(int sz)

{

  m_iSize = 0;  CreateSize(sz);

}

TestMemory::~TestMemory () { delete[] TestMemory1; TestMemory1 = NULL; }

int TestMemory::FindSize () { return m_iSize; }

void TestMemory::CreateSize(int minSize)

{

if(m_iSize < minSize)

{

byte* newmem = new byte[minSize];

memset(newmem + m_iSize, 0, minSize - m_iSize);

memcpy(newmem, TestMemory1, m_iSize);

delete []TestMemory1;

TestMemory1 = newmem;

m_iSize = minSize;

}

}

byte* TestMemory::pointer ()

  { return TestMemory1; }

byte* TestMemory::pointer(int minSize)

{

CreateSize(minSize);

return TestMemory1;

} ///:~



In the main function the
int _tmain (int argc, _TCHAR* argv[])
{
  TestMemory ocTest (20);
   int iSize = ocTest.FindSize ();
   cout << iSize << endl;
  getchar ();
return 0;
}
You can see that CreateSize( ) is the only function responsible for allocating memory, and that it is used from the second constructor and the second overloaded form of pointer( ).
Inside CreateSize( ) , nothing needs to be done if the size is large enough. If new storage must be allocated in order to make the block big, the new “extra” portion is set to zero using the Standard C library function memset ( ),
At final, the old memory is deleted and the new memory and sizes are assigned to the appropriate members.
The TestMemory class is designed to be used as a tool within other classes to simplify their memory management.
 Testing of the above TestMemory class
#include "stdafx.h"

#include <iostream>

#include <stdio.h>

#include <cstring>

using namespace std;

#ifndef TESTMEMORY_H

#define TESTMEMORY_H

typedef unsigned char byte;

class TestMemory {

int m_iSize;

byte* TestMemory1;

void CreateSize (int minSize);

public:

TestMemory ();  // constructor of the class

TestMemory (int sz);  // parameterized constructor of the class

~TestMemory (); // destructor of the class

int FindSize ();  //  Find the size

byte* GetBytes ();  // get the GetBytes

byte* GetBytes (int minSize);   // return the GetBytes

};

#endif // TESTMEMORY_H ///:~

TestMemory::TestMemory ()

  {   TestMemory1 = NULL; m_iSize = 0; }

TestMemory::TestMemory(int sz)

{

  m_iSize = 0;

  CreateSize(sz);

}

TestMemory::~TestMemory () { delete[] TestMemory1; TestMemory1 = NULL; }

int TestMemory::FindSize () { return m_iSize; }

void TestMemory::CreateSize(int minSize)

{

if(m_iSize < minSize)

{



byte* newmem = new byte[minSize];

memset(newmem + m_iSize, 0, minSize - m_iSize);

memcpy(newmem, TestMemory1, m_iSize);

delete []TestMemory1;

TestMemory1 = newmem;

m_iSize = minSize;

}

}

byte* TestMemory::GetBytes ()

  { return TestMemory1; }

byte* TestMemory::GetBytes(int minSize)

{

CreateSize(minSize);

return TestMemory1;

} ///:~

class TestMyString {

TestMemory* buf;

public:

TestMyString ();

TestMyString(char* str);

~TestMyString();

void concat(char* str);

void print(ostream& os);

};

TestMyString::TestMyString() { buf = 0; }

TestMyString::TestMyString(char* str) {

buf = new TestMemory(strlen(str) + 1);

strcpy((char*)buf->GetBytes(), str);

}

void TestMyString::concat(char* str) {

if(!buf) buf = new TestMemory;

strcat((char*)buf->GetBytes (buf->GetBytes () + strlen(str) + 1), str);

}

void TestMyString::print (ostream& os) {

if(!buf) return;

os << buf->FindSize () << endl;

}

TestMyString::~TestMyString() { delete buf; }

int main() {

TestMyString s("My test string");

s.print(cout);

s.concat(" some additional stuff");

s.print(cout);

TestMyString s2;

s2.concat("Using default constructor");

s2.print(cout);

}

int _tmain (int argc, _TCHAR* argv[])

{

  TestMemory ocTest (20);

   int iSize = ocTest.FindSize ();

   cout << iSize << endl;

   byte* ocByte = ocTest.GetBytes  (30);

   cout << ocByte[1] << endl;

   getchar ();

   return 0;

}


All you can do with this class is to create a TestMyString, concatenate text, and print to an ostream. The class only contains a pointer to a TestMemory, but note the distinction between the default constructor, which sets the pointer to zero, and the parameterized constructor, which creates a TestMemory and copies data into it.
We need to modify the constructor to get the efficiency back as seen below:
TestMyString::TestMyString(char* pchStr) {

if(!*pchStr) { // Pointing at an empty string

buf = 0;

return;

}

buf = new TestMemory(strlen(pchStr) + 1);

pchStrcpy((char*)buf->pointer(), pchStr);

}

On the other hand, consider the TestMemory class. If you look at the definitions of the two constructors and the two pointer( ) functions, you can see that using default arguments in both cases will not cause the member function definitions to change at all. Thus, the class could easily be rewrite like this, in this we have to notice that a call to CreateSize (0) will always be quite efficient.

//: C07:TestMemory2.h

#ifndef TESTMEMORY2_H

#define TESTMEMORY2_H

typedef unsigned char byte;

class TestMemory {

byte* TestMemory;

int m_isize;

void CreateSize(int minSize);

public:

TestMemory(int sz = 0);

~TestMemory();

int GetSize();

byte* pointer(int minSize = 0);

};

#endif // TESTMEMORY2_H ///:~




No comments: