14. Advanced Overloading Techniques

About this Tutorial –

Objectives –

This course is aimed at students who need to get up to speed in C++. The course introduces object-oriented concepts and shows how they are implemented in C++. The course does not require awareness or familiarity with object-oriented programming techniques, but programming experience would be useful but not necessarily required.

Audience

Students who are new to object orientation (or programming) and need to learn C++.

Prerequisites

No previous experience in C++ programming is required. But any experience you do have in programming will help. Also no experience in Visual Studio is required. But again any experience you do have with programming development environments will be a valuable.

Contents

The C++ course covers these topics and more:

  • Introduction to C++: Key features of C++; Defining variables; Formulating expressions and statements; Built-in data types; Console input/output
  • Operators and types: Assignment; Compound Assignment; Increment and decrement operators; Const declarations; Type conversions
  • Going Further with Data Types: Enumerations; Arrays; Using the standard vector class; Using the standard string class; Structures

Download Solutions

Java tutorial


Overview

Estimated Time – 0.5 Hours

Not what you are looking? Try the next tutorial – Templates

Lab 1: Conversions

Lab 1: Conversions
  1. Overview of Conversions
    • “Conversions” are when a value is converted from one data type to another
      • E.g. from an int to a double (or vice-versa)
      • E.g. from an object (such as a Person object) to a string
      • Etc…
    • This section of the chapter takes a closer look at how conversions work in C++
      • We explore the “built-in” conversions in the C++ language
      • We also explore how to define additional “custom” conversions
  2. Implicit Conversions
    • An implicit conversion is one that happens automatically
      • i.e. you don’t have to tell the compiler to do it
    • C++ performs implicit conversions in the following cases:
      • Widening conversions, e.g. from int to double
        int i = 42;
        double d = i; // Implicit conversion from int to double
      • From non-const-pointer to const-pointer
        Person *p = new Person("John");
        const Person *cp = p; // Implicit conversion from Person* to const Person*
      • From pointer to void-pointer (remember, a void pointer is a special kind of pointer in C++, which can point to anything)
        Person *p = new Person("John");
        void *pv = p; // Implicit conversion from Person* to void*
Lab
  1. Defining an Employee class
    • In Visual Studio, create a new C++ project named CopyingAssignmentApp in the student folder.
    • Define a simple class named Employee as follows:
      • The class should have data members to holds an employee’s name, salary, and employee ID
        string name;
        double salary;
        int employeeID;
      • The class should have some simple methods to give a pay rise, display details, etc…
        Employee::Employee(const string name,double salary,int eID) : name(name) , salary(salary),employeeID(eID)
        {
        }
        string Employee::ToString() const
        {
         stringstream oss;
         oss << "name: " << name << ", salary: " << salary << ", employee id: " << employeeID;  return oss.str(); } string Employee::GetName() const {  return name; }
      • View code file.

Lab 2: New conversion syntax in C++

Lab 2: New conversion syntax in C++
  1. Overview
    • C++ supports some more explicit syntax for conversions
      • Better than original syntax (see 1st section of this chapter), because the purpose is clearer
    • The new conversion mechanisms are:
      • static_cast
      • const_cast
      • reinterpret_cast
      • dynamic_cast
  2. Static Casts
    • static_cast
      • Use this for simple conversions
      • e.g. narrowing from a double to an int
        double d = 3.14;
        int i = static_cast<int>(d);
  3. Const Casts
    • const_cast
      • Use for conversions that relate only to const-ness
      • i.e. convert a non-const-pointer to a const-pointer (or vice versa)
        // This is a const pointer...
        const Person *cp = new Person("John");
        // Cast into a non-const-pointer (e.g. if you really do need to modify the object).
        Person *p = const_cast<Person*>(cp);
  4. Reinterpret Casts
    • reinterpret_cast
      • Use if you want to treat underlying types completely differently
      • e.g. to treat an address as a simple number (why would you need to do this...?)
        Person *p = new Person("John");
        int addressAsNumber = reinterpet_cast<int>(p);
  5. Dynamic Casts
    • dynamic_cast
      • Use if you want to cast a base-class-pointer to a derived type
      • Gives back a null pointer if the object isn't really that type
      • Allows you to test the real type a pointer points to
      • Note: doesn't work in MFC (use reinterpet_cast instead)
    • Example:
      T14P1
      void SomeMethod(Person *p)
      {
       Student * pStud = dynamic_cast(p);
       if (pStud != 0)
       {
        // Use Student-specific methods etc here...
       }
      }
Lab
  1. Implementing conversion operators on Employee
    • Implement the following conversion operators in Employee:
      • Convert an Employee to a string (i.e. the employee's name)
        Employee::operator string() const
        {
         return name;
        }
      • Convert an Employee to an int (i.e. the employee's ID number
        Employee::operator int() const
        {
         return employeeID;
        }
      • View code file.
    • In main(), create some Employee objects and test these conversion operators
      Employee e0("Jayne", 10000, 100);
      Employee e1("Andy", 10100, 101);
      Employee e2("Emily", 10200, 102);
      string str = e1;
      cout << str << endl;
    • View code file.

Lab 3: User-defined conversions

Lab 3: User-defined conversions
  1. Overview of User-Defined Conversions
    • You can define conversion operators in a class
      • Converts your object into the specified type
    • A conversion operator is a member function in your class, with the following general syntax:
      • operator type()
  2. Rules for User-Defined Conversions
    • User-defined conversion operators must follow these rules:
      • Must be a member function in your class
        • i.e. not a friend function or a global function
      • No return type
        • Return type is implied by name of function
      • No parameters
        • Because cast operators are unary
      • Should probably be const
        • Because cast operators don't change original object
  3. Example:
    • Define a conversion operator that converts a Person object to a string
      // Header
      class Person
      {
      public:
       operator string() const;
       ...
      };
      // Source
      Person::operator string() const
      {
       // Must return correct type!
       return this->name; // etc.
      }
      // Usage
      Person person1("John");
      string str1 = person1;     // Implicitly calls operator string()
      string str2 = (string)person1; // Can use explicit syntax if you like
      string str3 = person1.operator string();   // This also works!
      string str4 = static_cast(person1); // So does this!
Lab
  1. Defining a Staff class to hold a collection of Employees
    • Define a class named Staff, which contains a fixed-size array of Employee objects. The constructor should take an integer specifying the array-size.
      int size;
      Employee * employees;
      static Employee dummy;
      Staff::Staff(int size) : size(size)
      {
       employees = (new Employee[size]);
      }
    • View code file.
    • In the Staff class, implement operator[] to provide access to an employee at the specified index position, e.g. staff[10] should return a reference to element 10 in the underlying array. Take care of const-ness carefully. Also think what to do if index is out of range...
      Employee& Staff::operator[](int id) const
      {
       if (id < 0 || id > size)
       {
        return dummy;
       }
       else
       {
        return employees[id];
       }
      }
    • View code file.
    • Also implement operator[] to provide access to an employee with a specified name, e.g. staff["Smith"] should return a reference to the first employee element whose name is "Wayne". This will involve a linear search... Also think what to do if name isn't found...
      Employee& Staff::operator[](string name) const
      {
       for (int i = 0; i < size; i++)  {   if (employees[i].GetName() == name)   {    return employees[i];   }  }  return dummy; }
    • View code file.
    • Add code in main(), to test your Staff class thoroughly
      Staff s(10);
      s.Insert(e0, 0);
      s.Insert(e1, 1);
      s.Insert(e2, 2);
      s.Insert(e3, 3);
      s.Insert(e4, 4);
      cout << "Enter an array index between 0 and " << s.NumEmps() - 1 << ": "; int index; cin >> index;
      Employee emp = s[index];
      cout << "Full details via ToString(): " << emp.ToString() << endl; cout << "Employee cast to a string: " << (string)emp << endl; cout << "Employee cast to an int: " << (int)emp << endl;
    • View code file.

Lab 4: Indexing

Lab 4: Indexing
  1. Built-in Indexing with Arrays
    • Arrays in C++ (and C) have language-level support for indexing
      • Via the [] operator, with a zero-based integer index
    • Example:
      string teams[] = { "Liverpool", "Man U", "Swansea" };
      string bestTeam = teams[2];
  2. User-Defined Indexing
    • You can define index operators in a class
      • Useful if your class wraps a collection of items
      • Allows array-like syntax to items
    • Syntax:
      • refReturnType operator [] (index parameter)
    • Notes:
      • Must be a member function
        • i.e. not a friend or global
      • Returns a reference to an item
        • Allows [] to be used on left-hand-side of assignment
      • Takes an index as a parameter
        • Typically int, but doesn't have to be
      • Should probably be const
        • But see later...
  3. Example - Declaring Operator []
    • Define an index operator to get item in SafeIntArray object
      class SafeIntArray
      {
      public:
       SafeIntArray(int length);
       ~SafeIntArray();
       int& operator[](int idx) const;
       int GetLength() const
       {
        return length;
       }
      private:
       int length;
       int * pData;
       static int dummyInt;  // This is what we'll return if illegal access attempt.
      };
  4. Example - Implementing Operator []
    • Here's the implementation of the operator[] function, plus the other members in the class
      #include "SafeIntArray.h"
      int SafeIntArray::dummyInt = -1;
      SafeIntArray::SafeIntArray(int length)
       : length(length),
        pData(new int[length])
      {
      }
      SafeIntArray::~SafeIntArray()
      {
       delete [] pData;
      }
      int& SafeIntArray::operator[](int idx) const
      {
       if (idx < 0 || idx > this->length)
        return dummyInt;
       else
        return this->pData[idx];
      }
  5. Example - Using Operator []
    • Here's some client code that shows how to use operator[] to access items in internal collection
      SafeIntArray myInts(4); // Contains items at indices 0, 1, 2, 3.
      ...
      for (int i = 0; i < myInts.GetLength(); i++) {  // Can use [] as lvalue (because it returns a reference to an item in the array).  myInts[i] = i * 100;  // Equivalent syntax:  myInts.operator[](i) = i * 100; } cout << "My array of integers: " << endl; for (int i = 0; i < myInts.GetLength(); i++) {  // Can also use [] as an rvalue.  cout << "\t" << myInts[i] << endl; }
  6. Overloading on const-ness
    • You can define 2 very similar versions of operator[]
      • One is a const member function
      • Returns a const reference
      • Compiler will call this version if you use [] on a const object
        const int& operator[](int idx) const;
        // Const function.
        // Returns const ref to ensure client can't // change the returned value
      • The other is a non-const member function
      • Returns a non-const reference
      • Compiler will call this version if you use [] on a non-const object
        int& operator[](int idx);
        // Non-const function.
        // Returns non-const ref to allow client to change the
        // returned value.
  7. Non-integer Indexing
    • The parameter to operator[] doesn't have to be an int
      • E.g. it could be a string
      • Useful in scenarios such as an associative map (keys are strings, values are objects)
    • Trivial example:
      // Header
      class SafeIntArray
      {
      public:
       int& operator[](string idx) const;
       ...
      };
      // Source
      int& SafeIntArray::operator[](string idx) const
      {
       if (idx == "zero") return pData[0];
       else if (idx == "one") return pData[1];
       else if (idx == "two") return pData[2];
       else if (idx == "three") return pData[3];
       else ... do something else ...
      }
      // Usage
      SafeIntArray yourInts(4);
      yourInts["zero"] = 1000; // Puts 1000 at index 0.

 

Well done. You have completed the tutorial in the C++ course. The next tutorial is

15. Templates


Back to beginning
Copyright © 2016 TalkIT®






If you liked this post, please comment with your suggestions to help others.
If you would like to see more content like this in the future, please fill-in our quick survey.
Scroll to Top