C++ course

Lesson 4 recap

Objectives

C++ extra systax

- References

- Static keyword

- Process memory mapping 

- this keyword

- const keyword

- Implicit conversion

- explicit keyword

C++ types

- std::string

 

 

References

Creating a reference is essential creating another name for a variable

int   i = 42;
int&  refInt = i;
int   i = 42;
int&  refInt1; // Illegal, must be initialled 
int&  refInt2 = i;
int j = 100;
refInt2 = j;   // Illegal. once initialled refetene value can't change

a reference must be initialised when it's declared, value change disallowed.

void swap (int& first, int& second)
{
  int temp = first;
  first = second;
  second = temp;
}

Previously, swap function required pointer, no longer with references

Difference between pointers & references

- Pointers need not be initialised, references do

- References simplify code 

- No need to verify if references are initialised, that's a precondition

References - advantages

Prior to references C only had send by value.

struct VeryBigStruct {
/* ... */
};

void foo(VeryBigStruct vbs) {
  /* Handle code */
}

int main() {
    VeryBigStruct v1;
    foo(v1); // VeryBigStruct is copied. send by value
}
void foo(const VeryBigStruct* vbs) {
  if (vbs != NULL) {
     /* Handle code via pointer */
  }
}

int main() {
    VeryBigStruct v1;
    foo(&vbs); // VeryBigStruct is not copied. send the location of the struct
}

To avoid this overhead C programmers sent the address of VeryBigStruct

Using references we don't need to change the functions code, nor use pointers.


void foo(const VeryBigStruct& vbs) // Only function signature was changed 
 

Reference - cont

int& foo() 
{
   int i = 10;
   return i;  // Here it's not i's value returning 
              // but rather a reference to i
}  

int& refI = foo(); // Dangerous, most compilers don't com pain
int& fun()
{
    static int x = 10;  // Static means x is valid outside fun()
    return x;           // returns a reference to int (int&)
}

int main()
{
    fun() = 30; // fun() returns a reference to x. so value of x updated 
    cout << fun();
    return 0;
}

Potential problem

Peculiar usage, not illegal.

Static 

Usage in C language

- Restrict the visibility of a symbol to the current translation unit  (TU).

 

static int i=10;   // Can be used only in current TU
static int foo();  //             - " -

- When used in function the variable is allocated statically (compile time) and is valid for the entire run time of the program.

void getId() {
  static int id = 1;  // Initialisation happens only first time getId() is called
  return id++;        // Id exist in static memory and is not destructed when end scoped reached
}

Extra usage in C++

- in a class, static means that the method or attribute belongs to the class and not to a specific instance

class Test {
  public:
    static int foo() { /* code */ }
           int bar() { /* code */ }
};

Test::foo(); // static method can be called without instance
Test::bar(); // Error. bar is not static and can not be called without instance

the this keyword

Another angle to view statics is understanding what happens when we call to a non-static function.

class Test {
  public:
     static void foo() { /* code */ }
            void bar() { /* code */ }
};

Test t;
t.bar(); // Actually calls bar(&t) 

Each none static method expects to receive this as the first parameter. this is just the pointer to the object and the compiler is automatically adding it when the method is called on an instance.

Process memory mapping

// Globals are static memory
int foo;        // Global, BSS segment
static int bar; // Global, BSS segment

int foo1 = 42;  // Global, Data segment
static bar1= 7; // Global, Data segment

void foobar() {
  static int id;// In BSS Segment
}

void main() {

  // Run-time memory.
  int a;               // In Stack
  int* pInt = new int; // In Heap

  // Static memory
  static int b = 42;   // In Data segment
  static int c;        // In BSS segment

}

Run-time memory = memory allocated while program is running

Static memory = memory allocated during complication

Const keyword

the basic use of const is to declare a constant 

const double pi = 3.1415926;

but when pointers are involved there is a bit more to it

int i = 42;
const int*  pI1 = &i; // the value pointed at is constant 
int const * pI2 = &i; // Same as above

// While 
int * const = &i      // The pointer is constant

References can't change, but the still have 2 possible syntaxes

int i = 42;
const int&  rI1 = i; 
int const & rI2 = i; 

Const keyword - functions

// v───v───v───v───v───v───v───v───v───v───v───v─┬┐
//                                               ││
//  v──#1    v─#2             v──#3    v─#4      #5
   int const * const Method3(int const * const&) const;

To be read from write to left

#5 says that the entire function declaration to the left is const, implies that this is necessarily a member function rather than a free function.

#4 says that the pointer to the left is const (may not be changed to point to a different address).

#3 says that the int to the left is const (may not be changed to have a different value).

#2 says that the pointer to the left is const.

#1 says that the int to the left is const.

Const - why?

Programmers should always make clear when they intend values to not be changed.

- It allows compiler to optimise code

- It prevents human error of updating memory unintentionally.

It also allows the compiler to assist the programmer

void foo1(char* str)  { } 
void foo2(string str) { }
void foo3(string& str) { }
void foo4(const string& str) { }


string s("two");

foo1("one");   // Okay
foo1(s);       // Not okay, foo1 doesn't accept string

foo2("one");   // Works, but constructs string from C String than copies it 
foo2(s1);      // Works, but copies s1 

foo3("one");   // Not okay, "one" is not a reference to string
foo3(s1);      // Okay.

foo4("one");   // Okay, due to it being const the compiler constructs
               //       a string from C String and sends a reference
foo4(s1);      // Okay. 

Implicit conversion

The compiler will use a one argument construct to implicitly convert

class IntClass {
  public:
    IntClass(int input):value(input) {} 
    
  private:
    int value;
};


void foo(const IntClass& i)  { }


foo(10); // The compiler will try to satisfy this call
         // IntClass will be constructed from int 
class IntClass {
  public:
    IntClass(int input1, int input2 = 50):value1(input1), value2(input2) {} 
    
  private:
    int value;
    int value2;
};


void foo(const IntClass& i)  { }


foo(10); // The compiler will try to satisfy this call
         // IntClass will be constructed from int 

Constructors with more than one parameter can also be used.

Implicit conversion considred undesirable 

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

class Rational 
{
    public:

    Rational(int num, int den=1):m_numerator(num), m_denominator(den) {}
    string asString() const;  // Returns the string representation for printing
        
    bool isEqual(const Rational& other) const;  
    
    private:
    int m_numerator;
    int m_denominator;
};

string Rational::asString() const
{
    stringstream ss;
    ss << m_numerator << "/" << m_denominator;
    return ss.str();
}

bool Rational::isEqual(const Rational& other) const
{
    return (other.m_numerator * m_denominator) == (m_numerator * other.m_denominator);
}

int main()
{
   Rational r1(1,2);
   Rational r2(2,4);
   Rational r3(3,4);
   
   cout << r1.asString() << " == " << r2.asString() << "? " <<  (r1.isEqual(r2) ? "True" : "False") << endl;   
   cout << r1.asString() << " == " << r3.asString() << "? " <<  (r1.isEqual(r3) ? "True" : "False") << endl;   
   cout << r1.asString() << " == " << 3  << "? " <<  (r1.isEqual(3) ? "True" : "False") << endl;    // Expected conversion
   cout << r1.asString() << " == " << 0.5 << "? " <<  (r1.isEqual(0.5) ? "True" : "False") << endl; // Unexpected conversion 
}

The explicit keyword

To avoid this implicit conversion use the explicit keyword.

class IntClass {
  public:
    explicit IntClass(int input):value(input) {} 
    
  private:
    int value;
};


void foo(const IntClass& i)  { }


foo(10); // Not allowed anymore

foo( static_cast<IntClass>(10) ); // Allowed, explicitly requested by the programmer.

String library type

In C++ the std::string is introduced, it provides neutral and "intuitive" interface to manipulate strings.

#include <string>
using namespace std;

string s1("one");

s1 + " " + "two";  // "one two"
cin >> s1;         // read string to s1


cout << s1;        // output s1
s1.size();         // size of s1

s1[0] = 'A';  // Assign the first character of s1 an A.

To be used must include <string> header

Full string interface can be found in cplusplus reference page.

C++L04

By perplexedpigmy