Chapter 2
Basic facilities, Part 1

Kurt Nørmark
Department of Computer Science, Aalborg University


Abstract
Previous lecture Next lecture
Index References Contents
In this lecture we discuss selected, basic facilities in C++, as covered in Part 1 of The C++ Programming Language (version 3).

Basic facilities - in this lecture
Slide Contents Index
References 

Basic C++ facilities beyond the facilities of ANSI C

  • Basic types. Structs in C++.

  • Declarations and definitions

  • The general object concept in C++

  • C++ references

  • Parameter passing

  • Auto

  • Initialization

  • Rvalue references

  • Constness

Reference

Fundamental types i C++
Slide Contents Index
References 

An overview of the fundamental types in C++

Reference

  • A boolean type

    • bool

  • Character types, most importantly char

  • Integer types

  • Floating point types

  • Enumeration types

  • Type void (no value)

  • Pointer types

    • Including function pointers

  • Array types

  • Reference types

  • Struct and class types

Booleans
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Hurtig hen over

There is a type bool in C++

Boolean constants true and false

Reference
  • The C++ Prog. Lang. (3. edition): Page 71

Reference
  • The C++ Prog. Lang. (4. edition): Page 139

  • Type bool in relation to other fundamental types

    • Boolean values are converted implicitly to integers in arithmetic and logical expressions: false to 0 and true to 1.

    • Integers can be converted implicitly to booleans: 0 to false, other values to true.

    • Pointers can implicitly be converted to boolean values as well

Under the hood the well-known C boolean conventions still apply

Structs in C++
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Hurtig hen over

Structs and classes are almost identical concepts in C++

Reference
  • The C++ Prog. Lang. (3. edition): Page 234

Reference
  • The C++ Prog. Lang. (4. edition): Page 47, 454

Reference

  • C structs in relation to C++ structs

    • Similar to each other

    • In C++ it is possible to refer to struct S {...} by just S, not necessarily struct S

    • Both structs in C and C++ are associated with value semantics

  • C++ structs in relation to C++ classes

    • A struct is a class where all members are public by default

    • A struct is typcically used for aggregating public data

    • Both structs and classes can make use of inheritance

Declarations and definitions
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Vigtig sondring - eksempel programmet gennemgås omhyggeligt. Ikke svært.

It is important to be able to distinguish between declarations and definitions

Reference
  • The C++ Prog. Lang. (3. edition): Page 78

Reference
  • The C++ Prog. Lang. (4. edition): Page 152

  • Declaration

    • Introduces names - for the benefit of the compiler

    • Several declarations of the same name are allowed - must agree on the types involved

  • Definition

    • A declaration that also defines an entity

      • A location in memory

      • A function with a body

    • There must be precisely one definition of a named entity

    • The one-definition-rule (ODR) relaxes this a bit - for the benefit of multiple includes:

      • A class, inline function, or template may be defined more than once

      • if they appear in different translation units

      • if they are token-for-token identical

Program: Illustration of declarations and definitions - everything is fine.
#include <iostream>
#include <string>
using std::string;

string s;                 // DEFINES s to be the empty string.
int i = 5;                // DEFINES i as an int variable initialized to 5

struct Date{              // DEFINES Date to be a type (struct) with three
  int d, m, y;            // int fields: d, m, and y
};  

int f(int i){             // DEFINES f to a particular function from
  return i + 1;           // int to int
}

extern string t;          // DECLARES that t is a string
extern int j;             // DECLARES that j an int
struct DateWithWeekday;   // DECLARES that DateWithWeekday is a struct - forward declaration
int g(int i);             // DECLARES that g is an int returning function of int

DateWithWeekday 
           h(Date, int);  // DECLARES function h from Date and int to DateWithWeekday

struct DateWithWeekday{   // DEFINES an already forwardly declared type
  Date wd;                
  int weekday;
};

int func()                // DEFINES a parameterless function func
{
  Date d1 = Date();
  DateWithWeekday 
      dwd1,
      dwd2 = h(d1, 3);

  f(i);
  g(j);
}

Program: Illustration of declarations and definitions - several problems.
#include <iostream>
#include <string>
using std::string;

string s;                 // DEFINES s to be the empty string.
string s = "AP";          // Double definition: ERROR

int f(int i){             // DEFINES f to a particular function from
  return i + 1;           // int to int
}

int f(int j){             // DEFINES f again - double definition - ERROR
  return j - 1;           
}

double f(double j){       // DEFINES f on double - overload - OK
  return j - 1;           
}

int g(int);               // DECLARES g. OK

struct Date;              // DECLARES struct Date. OK

int f()                   // DEFINES the parameterless function f - an overload
{
  Date d;                 // Incomplete type. The details of of type Date must be known here. ERROR
  f(1);                   // OK
  g(2);                   // OK
}

Reference
  • The C++ Prog. Lang. (3. edition): ODR. Page 203

A definition is a declaration - a declaration is not necessarily a definition

The structure of a declaration
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Erfaringsmæssigt er dette nogle ting, som gør det svært for folk at læse C++ programmer. Allerede berørt i C delen af kurset. Frisk op, og vær sikker på at folk er med.

A declaration of a single entity consists of a four parts:

A base type, a declarator, a specifier (optional), and an initializer (optional)

Reference
  • The C++ Prog. Lang. (3. edition): Page 79 - 80

Reference
  • The C++ Prog. Lang. (4. edition): Page 153

Program: Examles of declarations.
  unsigned int i = 7;
  const double d = 5.7;
  char* str[] = {"This", "is", "a", "string", "array"};
  extern short int ei;
  bool is_even(int a);
  Point p1(1,2);
  Pair q1 = {3,4};

  • Base type

  • Declarator

    • The name being declared

    • Optional declarator operators - mimics their use as operators in expressions

  • Specifier:

    • Storage class: auto, extern, mutable, register, static, virtual

  • Initializer

    • Assignment-like

    • Function-like

    • Universal (C++11)

Program: More examples of declarations.
// Compilation: g++ -c -std=c++11 decl-str-3.cc 

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

struct Pair{int a, b;};

int main(){
  unsigned int i = 7;
  const double d = 5.7;
  std::string str[] = {"This", "is", "a", "string", "array"};  
  extern short int ei;
  bool is_even(int a);
  Point p1(1,2);    // Old style constructor syntax
  Point p2{3,4};    // New universal style initialization, "list initializer"
  Pair q1 = {5,6};  // Membervise initialization
  Pair q2{7,8};     // Ditto
}

Declaring several names together
Slide Contents Index
References 

Several comma-separated declarators - with associated initializers - may share the same base-type and specifier

Reference
  • The C++ Prog. Lang. (3. edition): Page 80

Reference
  • The C++ Prog. Lang. (4. edition): Page 154

Program: Examles of declarations of multiple names.
  unsigned int i = 7,  j[3],  *k = &i;

  char ch0;
  char* ch1, ch2;    // Misleading notation but OK.  Only ch1 is a char pointer!
  char *ch3, ch4;    // Prefer this variant!

  const double d = 5.7,  pi = 3.14159,  &dr = d;
  char *str[4],  ch = 'a';
  extern short int ei;
  bool is_even(int a), 
       is_odd(int a);
  Point p1(1,2), 
        p2;
  Pair q1 = {3,4}, 
       q2 = {5,6};

"Such constructs makes a program less readable and should be avoided"

Nevertheless, I use multiple name declarations a lot in these slides and notes

Declarations as statements - declarations in conditions
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Ganske ligefrem stof...

Introduce and initialize a variable at the place where it is first used

It is possible to delare variables in a condition of an if statement

Reference
  • The C++ Prog. Lang. (3. edition): Page 133, 135

Reference
  • The C++ Prog. Lang. (4. edition): Page 227

  • Declarations inside blocks

    • C89: All declarations appear before the first statement

    • C99 and C++: declarations and statements can be mixed

      • Avoids having all declarations first in block, and assignments later in the block

  • Declarations in the condition of an if statement

    • The scope of such a name is the rest of the if, including the else part

    • Serves as a scope restriction, compared with a declaration just before the if statement

Program: Declarations before statements - C89 Style. Some words about compilation of these programs: I use g++ to compile C++ programs. In most examples in this material, C++ files have file extension cc. Alternatively, cpp is also a popular file extension for C++ files. If gcc is activated on a cc or cpp file, it will activate the C++ compiler. To prevent this, use the compiler option -x c. Thus, to compile this file as a C89 c program, write gcc -x c -std=c89 -pedantic less-localized.cc
double g(int a, double d){
  return a * d;
}

void f(double p){
  int i = 0;            
  double result;        // Local variable result declared before the first statement.

  //...
  if (p <= 10.0) i++;   // Some statements here              
  //...

  result = g(i,p);      // result first used much later in the function.

  /* The rest of f comes here */
}

int main(){
  f(5.0);
}    

Program: A declaration is a statement in C++.
double g(int a, double d){
  return a * d;
}

void f(double p){
  int i = 0;

  // ...
  if (p <= 10.0) i++;        // Some statements
  // ...

  double result = g(i,p);    // Declaration of result the first time its is used.
                             
  /* Rest of f comes here  */
}

int main(){
  f(5.0);
}    

Program: A declaration in the condition of an if.
double g(int a, double d){
  return a * d;
}

double f(double p){
  int i = 0;

  if (p <= 10.0) i++;             // Some statements 

  if (double result = g(i,p)){    // A declaration in a condition
    return result * result;
  }
  else{
    return 1 / result;
  }

  /* Rest of f comes here */
}

int main(){
  f(5.0);
}    

The general notation of objects in C++
Slide Contents Index
References 

Objects in C++ have a generalized meaning compared to many other object-oriented programming languages

The concept object: An object is "something in memory"

Reference
  • The C++ Prog. Lang. (3. edition): Page 84

Reference
  • The C++ Prog. Lang. (4. edition): Page 165-166

  • The low-level notation of a C++ object

    • Something in memory - a contiguous region of storage

    • A variabele

    • An array

    • A struct

An instance of a class is object in both the low-level meaning, and in the well-established OOP meaning of the word

Reference

Lvalues
Slide Contents Index
References 

The concept object: An object is a contiguous region of storage - "something in memory"
The concept lvalue: An lvalue is an expression that refers to an objectThus, an lvalue is an expression that refers to a memory location. You can take the address of that memory location with the address operator.

Reference
  • The C++ Prog. Lang. (3. edition): Page 84

Reference
  • The C++ Prog. Lang. (4. edition): Page 165-166

  • Lvalues

    • Named after expressions that can occur at the left-hand side of an assignment

    • As such, lvalues are typically modifiable

    • Constant lvalues do also occur in C++ (in the context of so-called const references, §5.5)

Program: Examples of lvalues.
  var = 7;
  tab1[3] = 8;
  *(tab2 + 4) = 9;
  tab3[0].x = 2.0;

Rvalues
Slide Contents Index
References 

The concept rvalue: An rvalue is an expression that is not an lvalue - an expression whose value does not have a fixed position in memory, such as a temporary objectAn rvalue can be the result returned by a function, or the value of a literal expression.

Reference
  • The C++ Prog. Lang. (4. edition): Page 166

  • Rvalues

    • Expressions that can appear at the right side of the assignment

    • It does not make sense to take the address of an rvalue expression

Program: Examples of rvalues.
  double e = 3.14;
  double d = f(5, e);
  int i = 5, k = i + 8;
  bool b = Point{1,2} == Point{3,4};

  double *pe = &3.14;     // error: Cannot take the address of a 3.14
  double *pd = &f(5, e);  // error: Cannot take the address of a f(5, e)
  int *pi = &(i + 8);     // error: Cannot take the address of (i + 8)  

Program: The rvalue example - in a bit of context.
#include <iostream>
#include <string>
#include "point.h"

double f(int i, double d){return i + d;}

int main(){
  double e = 3.14;
  double d = f(5, e);
  int i = 5, k = i + 8;
  bool b = Point{1,2} == Point{3,4};

  double *pe = &3.14;     // error: Cannot take the address of a 3.14
  double *pd = &f(5, e);  // error: Cannot take the address of a f(5, e)
  int *pi = &(i + 8);     // error: Cannot take the address of (i + 8)   
}

An expression (in a given context) is either an Lvalue or an Rvalue - not both

Reference
  • The C++ Prog. Lang. (4. edition): Page 166


C++ References

References
Slide Contents Index
References 

A reference in C++ is an alias

A reference is an alternative name for an object

References

Program: C++ References.
  int k = 3;
  double a = 5.0;
  double &d = a;
  void f(int &i, double &d);
  f(k,a);

Reference
  • The C++ Prog. Lang. (3. edition): Page 97

Reference
  • The C++ Prog. Lang. (4. edition): Page 189

  • Why references in C++?

    • An implementation of call-by-reference parameters - instead of relying on pointers passed by value

    • An optimization of large call-by-value parameters - by means of const references (meaning: a reference to a constant)

      • Name binding to temporary objects

    • Essential for programming parameters of copy constructors and assignment operator overloads

A reference in C++ can be understood as a generalization of "call by reference parameters"

Thus, C++ references are not just related to parameter mechanisms - they represent a broader concept

Reference
  • The C++ Prog. Lang. (3. edition): Argument passing. Value return. Page 145-148

Reference
  • The C++ Prog. Lang. (4. edition): Argument passing. Page 316-318

Reference
  • The C++ Prog. Lang. (4. edition): Value return. Page 310

Reference

Rules for references
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
...

Program: C++ References.
  int k = 3;
  double a = 5.0;
  double &d = a;
  void f(int &i, double &d);
  f(k,a);

  • A reference must be initialized when declared

  • A reference is constant by nature

    • Once established the reference can never be set to reference something else

  • No operator operates on a reference as such - only the object referenced

  • There is no null reference (in the sense that there is a nullptr)

  • Pointers to references and arrays of references do not exist

    • But references to pointers and references to array can exists

Reference
  • The C++ Prog. Lang. (3. edition): Page 146

Reference
  • The C++ Prog. Lang. (4. edition): Page 316

References - Examples
Slide Contents Index
References 

Here we show a number of examples that illustrate various aspects of references

"The absence of const in a declaration of a reference (argument) is taken as a statement of intent to modify the variable"

Program: A variable becomes a reference to another variable.
// Very simple example - illustrates an alias e of d in a function f.

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

double f(double di = 6.0){
  double d = di,  // d initialized to the value of the parameter di
         &e = d;  // e is an alias to d

  e += 7.0;       // increasing e, and hereby d, by 7
  return d;
}

int main(){
  cout << f() << endl;   // 13
  cout << f(8) << endl;  // 15
}

Program: No operator operates on a reference as such.
// Illustrate references vs. pointers.
// Example similar to the function g on page 98 in 'The C++ Programming Language' (3ed)
// and on page 190 in 'The C++ Programming Language' (4ed).
// The morale is that ++ applied on a pointer does pointer arithmetic. 
// ++ applied on a reference does not affect the reference as such.

#include <iostream>
#include <string>

using namespace std;

void g(){

  // HERE WE ILLUSTRATE REFERENCES:
  int ii = 0;
  int& rr = ii;              // rr is a reference to ii - an alias to ii
  rr++;                      // ii is incremented.
                             // The reference is NOT incremented itself.
  cout << ii << endl;        // 1
  cout << rr << endl;        // 1

  // HERE WE DO SIMILAR THINGS WITH POINTERS:
  int* pp = &rr;             // pp is really the address of ii (via rr) - a pointer to ii.
                             // NOT a pointer to a reference!
  (*pp)++;                   // ii is incremented again, 
  pp++;                      // The pointer as such is incremented - pointer arithmetic.
                             // Not good...
  cout << ii  << endl;       // 2
  cout << *pp << endl;       // 2673944
  pp--;                      // Better revert to the original value
  cout << *pp << endl;       // Still 2. No harm has been done. 

}

int main(){
  g();
}

Program: A typical use of references: A number of results passed back from vector_min_max via references.
// Illustrates the use of references for output parameters.

#include <iostream>    
#include <string>
#include <vector>

// Return the minimum, index og min, maximum, and index of maximum via reference parameters.
// Assume as precondition that vec holds at least one element.
// In this version vec is pass by value. Better alternative: const reference.
void vector_min_max(std::vector<double> vec,
                    double& min, int& min_index, double& max, int& max_index){
  double cur_max{vec[0]},
         cur_min{vec[0]};
  int cur_min_index{0},
      cur_max_index{0};
  
  for(int i = 0; i < vec.size(); ++i){
    if (vec[i] > cur_max){
      cur_max = vec[i];
      cur_max_index = i;
    }

    if (vec[i] < cur_min){
      cur_min = vec[i];
      cur_min_index = i;
    }
  }       

  min = cur_min;  max = cur_max;
  min_index = cur_min_index;  max_index = cur_max_index;
}


int main () {
  using namespace std;

  vector<double> v{1.1, -3.5, 7, 9, 0, -0.5};
  double mi, ma;
  int i_mi, i_ma;

  vector_min_max(v, mi, i_mi, ma, i_ma);

  cout << "Min: " << mi << " at: " << i_mi << endl;
  cout << "Max: " << ma << " at: " << i_ma << endl;
}

Program: A function that attempts to return references to local variables.
// Annother illustration of C++ reference parameters. 
// Attempting to return a reference to a local variable. Compiles with warnings.

#include <iostream>
#include <string>

int& f(bool b){
  int i = 5, j = 10;

  std::cout << "i: " << i << "  ";
  std::cout << "j: " << j << std::endl;

  if (b)
    return i;     // error (warning) Reference to local variable returned.
  else 
    return j;     // error (warning): Reference to local variable returned.
}

int main()
{
  using namespace std;

  int a, b;
  a = b = 0;

  f(true) = 15;          
  f(false) = 20;         
  f(true) = 25;          
}

Program: Ditto - handling the problem by making the local variable static.
// Annother illustration of C++ reference parameters. 
// Returns a reference to local a static variable. Strange, but compiles and runs as expected.

#include <iostream>
#include <string>

int& f(bool b){
  static int i = 5, j = 10;

  std::cout << "i: " << i << "  ";
  std::cout << "j: " << j << std::endl;

  if (b)
    return i;     
  else 
    return j;     
}

int main()
{
  using namespace std;

  int a, b;
  a = b = 0;

  f(true) = 15;            // 5 10.  Then assigning 15 to i.
  f(false) = 20;           // 15 10. Then assigning 20 to j.
  f(true) = 25;            // 15 20. Then assigning 25 to i.
}

Program: A function with reference parameters and reference return type.
// Annother illustration of C++ reference parameters. 
// A rather strange example involving a function that returns a reference.

#include <iostream>
#include <string>

int& f(bool b, int& i, int& j){
  if (b)
    return i;
  else 
    return j;
}

int main()
{
  using namespace std;

  int a, b;
  a = b = 0;

  f(true, a, b) = 7;            // assigning to a
  cout << "a: " << a << endl;   // 7
  cout << "b: " << b << endl;   // 0

  a = b = 0;
  f(false, a, b) = 7;           // assigning to b
  cout << "a: " << a << endl;   // 0
  cout << "b: " << b << endl;   // 7
}

Program: Convenient references to long/deep fields.
// Illustrates how a reference can be used for naming convenience.
// A program with two versions of the function work_on_persons_road_number.

#include <iostream>
#include <string>

using namespace std;

typedef struct{
  char road[15];
  int roadNumber;
  char town[20];
  } address;   

typedef struct{
  int idNumber;
  char firstName[10],
       lastName[20];
  address location;} person;   

bool even(int n){
  return n%2 == 0;
}

// A function in which a long and deep field name is used many times.
void work_on_persons_road_number(person &p){
  if (even(p.location.roadNumber))
    p.location.roadNumber = p.location.roadNumber + 1;
  else
    p.location.roadNumber = 0;
}

// A version of the function that binds the roadNumber field to an
// int reference.
void work_on_persons_road_number_with_ref(person &p){
  int &lrn = p.location.roadNumber;
  if (even(lrn))
    lrn = lrn + 1;
  else
    lrn = 0;
}

void print_person(person &p){
  cout << p.firstName << " " << p.lastName << endl
       << p.location.road << " " << p.location.roadNumber << endl
       << p.location.town << endl << endl;
}
 
int main(){
  person morten = 
     {190583,                             /* Initializer      */
      "Morten", "Madsen",                 /* and only that... */
      {"Bredgade", 23, "Middelfart"}
     };

  print_person(morten);
  work_on_persons_road_number(morten);
  print_person(morten);
  work_on_persons_road_number_with_ref(morten);
  print_person(morten);
}

The The C++ Prog. Lang. (4. edition) example on page 192-193 is also very illustrative

Exercise 2.3. Another example/exercise with C++ references

On the accompanying slide we have shown a number of examples that illustrate different uses of reference types in C++.

Your task in this exercise is to come up with yet another good and convincing example of reference types in C++. (Please use your own fantasy - not some internet fantasy).

Your program can be seen as the solution to a programming exercise about references. Please provide a short formulation of this exercise.

Exercise 2.3. Pointers in combination with references

In this exercise we will explore pointers and references relative to each other. Play and learn! We do this in context of a function that returns the maximum of two doubles. Here is the function with call-by-value parameters:

  double max(double a, double b){
    return a < b ? b : a;
  }

In all cases below, program the max function, call it, make make sure you get the expected result from the call.

Please be aware that the cases become increasingly strange...

  1. Make a version with C-style call by reference parameters - pointers passed by value.
  2. Make a version with call by C++ references. Also, return a double&.
  3. Make a version with call by C++ const references instead of call by value parameters.
  4. Demonstrate that pointers to references do not exist.
  5. Make a version with references to pointers. Does that make sense to you?
  6. Next, make version with const references to pointers.
  7. Finally, a version with const references to pointers to double constants

Can you imagine other interesting variations?

Constant References
Slide Contents Index
References 

A constant reference is really a reference to a constant

The use of const in a declaration of a reference (argument) means that we do not want to change the referenced object

"An initializer for const T&   does not need to be an lvalue, or even of type T"

Reference
  • The C++ Prog. Lang. (3. edition): Page 98, 146, 148, 283

Reference
  • The C++ Prog. Lang. (4. edition): Page 191

Program: Const ref scheme.
  const T &var = expression;

  • Initialization of var - a reference to T

    • Implicit conversion from the type of expression to T is performed

    • The result is placed in a temporary variable of type T

    • var is bound to the tempory variable - which cannot be mutated

It would be undesirable and misleading to be able to modify var, because it is just a temporary variable.

Program: The initialization of const reference var from rvalue, with type conversion.
// Initializes a const reference with an rvalue, via type conversion.

#include <iostream>

int main(){

  const int &var = 5.3;  // var becomes a const reference to an rvalue 
                         // via some temporary variable. Involves implicit type conversion.

  std::cout << var << std::endl;   // 5

  var = 6;               // ERROR: assignment of read-only reference 'var'
}

Program: A similar program that initializes a user defined struct via a 'functional casting' constructor.
// Another example of type conversion (to a user-defined type) before the binding of the const reference.

#include <iostream>
#include <string>
#include <cmath>

struct TwoDoubles{
  double f1, f2;

  TwoDoubles(double d): f1{d/2}, f2{d/2}{  // A TwoDobles object can be constructed from a double
  }

};


int main(){
  using namespace std;

  const TwoDoubles &var = 6.4;             // A temporary TwoDoubles object is made, by
                                           // activating the Twodoubles constructor on 6.4.
                                           // var becomes a const reference to the
                                           // TwoDoubles object.

  cout << var.f1 << ", " << var.f2 << endl;  // 3.2,  3.2
}

Program: Use of a const reference in the vector_min_max function (alread encountered in this lecture).
// Using a const reference as an alternative to a call-by-value parameter (avoids copying large objects).
// This is a real-world scenario - in contrast to some of the previous examples.

#include <iostream>    
#include <string>
#include <vector>

// Assume as precondition that vec holds at least one element.
// In this version vec is pass by const reference, which is more efficient than 
// passing it by value (and by a copy).
void vector_min_max(const std::vector<double>& vec,
                    double& min, int& min_index, double& max, int&max_index){
  double cur_max{vec[0]},
         cur_min{vec[0]};
  int cur_min_index{0},
      cur_max_index{0};
  
  for(int i = 0; i < vec.size(); ++i){
    if (vec[i] > cur_max){
      cur_max = vec[i];
      cur_max_index = i;
    }

    if (vec[i] < cur_min){
      cur_min = vec[i];
      cur_min_index = i;
    }
  }       

  min = cur_min;  max = cur_max;
  min_index = cur_min_index;  max_index = cur_max_index;
}


int main () {
  using namespace std;

  vector<double> v{1.1, -3.5, 7, 9, 0, -0.5};
  double mi, ma;
  int i_mi, i_ma;

  vector_min_max(v, mi, i_mi, ma, i_ma);

  cout << "Min: " << mi << " at: " << i_mi << endl;
  cout << "Max: " << ma << " at: " << i_ma << endl;
}

Program: Illustrates that it is not good to return a const reference to a deallocated local variable.
// Illustrates that it is dangerous to have a (const) reference to a deallocated variable.  
// Causes a warning from the compiler.

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

typedef int T;

const T& f(double d){
  double e = 2 * d;
  return e;                      // Compiler warning:
                                 // returning reference to temporary
}

int main(){
  double expression = 5.3;

  const T &var = f(expression);  
                                 
  cout << var << endl;           // ??
}

Lvalue References versus Pointers
Slide Contents Index
References 

Examples that compare programming with pointers and C++ references in the swap function

Program: Two versions of swap - with references and with pointers.
#include <iostream>
using namespace std;

void swap_doubles_by_ref(double &d1, double &d2){
  double temp;
  temp = d1;
  d1 = d2;
  d2 = temp;
}

void swap_doubles_by_ptr(double *d1, double *d2){
  double temp;
  temp = *d1;
  *d1 = *d2;
  *d2 = temp;
}

int main(){
  double e, f;

  e = 5.0, f = 7.0;
  cout << e << " " << f << endl;   // 5 7
  swap_doubles_by_ref(e, f);  
  cout << e << " " << f << endl;   // 7 5

  e = 5.0, f = 7.0;
  cout << e << " " << f << endl;   // 5 7
  swap_doubles_by_ptr(&e, &f);  
  cout << e << " " << f << endl;   // 7 5
}

  • Observations

    • The notational overhead - use of & and * - is less for use of references than for pointers

      • The reason is that it is not possible to manipulate the reference as such

    • The mental models are different

      • Pointers: Establish a pointer to an object, follow the pointer to the object for lhs/rhs access.

        • The pointer itself may be accidentally changed.

      • References: Establish an alternative name to an existing object (an alias).

        • Once established the reference can never be changed.

Reference
  • The C++ Prog. Lang. (4. edition): Page 189

A reference may be implemented as a constant pointer that is dereferenced automatically each time it is used

Parameter passing in C++
Slide Contents Index
References 

It is possible to pass parameters by value, by a pointer, and via a C++ reference

  • Call by value

    • Copy actual parameters and bind to formal parameters

      • Formal parameters are initialized - not assigned

      • For user-defined types: It is possible to control what copying means - via a copy constructor

      • In the copy constructor itself, call-by-C++-reference parameter passing is crucial

    • In the special case: Passing pointers by value (C-style call-by-reference)

  • Call by (C++) reference

    • The formal parameter becomes an alias of the actual parameter

      • If non-const, you intend to change the value of the actual parameter

    • Call by const reference is an attractive alternative to call by value parameters

      • No overhead due to copying

      • No risk of modifying the actual parameter via the formal parameter

Reference

Rvalue references
Slide Contents Index
References 

An rvalue reference is a reference to a temporary object (soon to disappear) from which we may be tempted to steal some constituents in order to avoid an expensive copy operation

References

Reference
  • The C++ Prog. Lang. (4. edition): Page 193

  • Rvalue references

    • Binds to an rvalue, such as the returned value of many functions

    • Used for "destructive read" that would otherwise have required a copy (Stroustrup citation)

    • We want to overload some functions on Rvalue references in order to avoid expensive copy operations

    • Intimately connected to move constructors

Program: Illustration of Rvalue references - in contrast to other kinds of references.
// Illustrates Rvalue references in relation to Lvalue references. DOES NOT COMPILE.

#include <iostream>    
#include <string>

using namespace std;

// A function that returns a string - an r-value.
string sf (string s, char ch){
  return s + ch;
}

int main () {
  string s1 {"AAU"};                   // s1 is initialized to "AAU"

  string& s2{s1} ;                     // s2 is a reference to s1.
  s2[0] = 'B';                         // Mutating s2 affects s1:
  cout << s1 << endl;                  // BAU

  string& s3 = sf("AA", 'U');          // Error: Cannot bind an Rvalue to Lvalue reference

  const string& s4 {sf("AA", 'U')};    // OK to bind an Rvalue to a const reference, however...
  cout << "s4: " << s4 << endl;        // s4: AAU

  string&& s5 {sf("AA", 'U')};         // It is problably most natural to bind the result of the sf call to an Rvalue reference.
                                       // Move constructor of string in use.
  cout << "s5: " << s5 << endl;        // s5: AAU

  string&& s6 = s1;                    // Error: Cannot bind an Lvalue to an Rvalue reference.

  string&& s7 {"AU"};                  // Perfect to bind "AU" to an Rvalue refence.
  cout << "s7: " << s7 << endl;        // s7: AU

  string&& s8 {s7};                    // Error: Cannot bind a string Lvalue to to an Rvalue.

  string&& s9 {move(s7)};              // We can cast s7 to an rvalue. Misleadingly named move, see The C++ Prog. Lang page 194-195.
  cout << "s9: " << s9 << endl;        // s9: AU
}

Program: The compilable parts of the program from above.
// The compilable parts of the previous program.

#include <iostream>    
#include <string>

using namespace std;

// A function that returns a string - an r-value.
string sf (string s, char ch){
  return s + ch;
}

int main () {
  string s1 {"AAU"};                   // s1 is initialized to "AAU"

  string& s2{s1} ;                     // s2 is a reference to s1.
  s2[0] = 'B';                         // Mutating s2 affects s1:
  cout << s1 << endl;                  // BAU

  const string& s4 {sf("AA", 'U')};    // OK to bind an Rvalue to a const reference, however...
  cout << "s4: " << s4 << endl;        // s4: AAU

  string&& s5 {sf("AA", 'U')};         // It is problably most natural to bind the result of the sf call to an Rvalue reference.
                                       // Move constructor of string in use.
  cout << "s5: " << s5 << endl;        // s5: AAU

  string&& s7 {"AU"};                  // Perfect to bind "AU" to an Rvalue refence.
  cout << "s7: " << s7 << endl;        // s7: AU

  string&& s9 {move(s7)};              // We can cast s7 to an rvalue. Misleadingly named move, see The C++ Prog. Lang page 194-195.
  cout << "s9: " << s9 << endl;        // s9: AU
}

Reference

Value return
Slide Contents Index
References 

The semantics of value return is that of initialization

Reference
  • The C++ Prog. Lang. (3. edition): Page 148

Reference
  • The C++ Prog. Lang. (4. edition): Value return. Page 308

  • Value return

    • A copy is returned, initializing an unnamed variable

    • The copy constructor is used - not the assignment operator

    • If a move constructor exists, it may be used (transparently)

  • Return of local variables

    • OK by value - efficient via move semantics

    • References or pointers to local (automatic) variables should not be returned

Three kinds of references
Slide Contents Index
References 

We describe and contrast the three kinds of references in C++

Using formulations and wordings from The C++ Prog. Lang. (4. edition)

  • Lvalue references

    • Refers to values we want to change

    • Useful alternatives for C-style 'call by reference' parameters (using pointers)

  • const Lvalue references

    • Refers to constants - values that we do not want to change

    • Useful alternative for 'call by value' parameters in many contexts

  • Rvalue references

    • Refer values that we do not want to preserve after we have used it

    • Useful in the context of value return from a function

    • Values that we intend to 'move from'

Reference
  • The C++ Prog. Lang. (4. edition): Page 190, 193

Lvalue references versus Rvalue references
Slide Contents Index
References 

A similar example that compares Lvalue and Rvalue references in the swap function

Program: Two versions of swap - with Lvalue references and Rvalue references.
// Illustrates move semantics (with rvalue references) in swap. One without, and one asking for use of move semantics.

#include <iostream>
#include <vector>

using namespace std;

template<typename T>
void swap(T& a, T& b){
  T temp {a};              // COPIES a to temp
  a = b;                   // COPIES b to b
  b = temp;                // COPIES temp to b
}

template<typename T>
void swap1(T& a, T& b){    // move forces a Rvalue reference
  T temp {move(a)};        // MOVES a to temp 
  a = move(b);             // MOVES b to a
  b = move(temp);          // MOVES temp to b
}

template<typename T>
void print_vector(const vector<T>& vec){
  for(auto e: vec) cout << e << " ";
  cout << endl << endl;
}

int main(){
  vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9},  // Two 'large' vectors
              w{5, 2, 0};                 

  print_vector(v);     // 1 2 3 4 5 6 7 8 9
  print_vector(w);     // 5 2 0
  swap(v, w);          // Uses swap by copying
  print_vector(v);     // 5 2 0
  print_vector(w);     // 1 2 3 4 5 6 7 8 9

  print_vector(v);     // 5 2 0
  print_vector(w);     // 1 2 3 4 5 6 7 8 9
  swap1(v, w);         // Uses swap by moving
  print_vector(v);     // 1 2 3 4 5 6 7 8 9
  print_vector(w);     // 5 2 0
}

Reference
  • The C++ Prog. Lang. (4. edition): Page 193-195

  • Observations

    • It may be expensive to use the copy constructor and the copy assignment on large objects

    • Forcing move semantics (by casting to a rvalue reference) alleviates the problem

Reference

Deduction of types with auto
Slide Contents Index
References 

auto can be used as a type specifier in C++11

auto deduces a type from an initializer

auto is also used when the return type of a function is written after the parameters (suffix return type syntax)

auto can be used for deduction of a function's return type in C++14

Reference
  • The C++ Prog. Lang. (4. edition): Page 163, 308

Reference
  • Effective Modern C++: auto type deduction. Item 2

Program: Sample use of auto in C++11.
// Illustrate various simple uses of auto i C++11

#include <iostream>    
#include <vector>
#include <cmath>    // abs
#include "point.h"



// Illustration of alternative return type - best if return type depends on parameters.
auto find_diagonal_points(std::vector<Point> points) -> std::vector<Point>{
  std::vector<Point> res;
  for(auto p: points)
    if(std::abs(p.getx())==std::abs(p.gety()))
      res.push_back(p);
  return res;
}

void without_auto(){
  int i{5};

  std::vector<Point> points = {Point{1,1}, Point{1,2}, Point{-1,1}, Point{-2,2}};
  std::vector<Point> diagonal_points = find_diagonal_points(points);
  for(Point p: diagonal_points)
    std::cout << p << std::endl;
}

void with_auto(){
  auto i = 5;       // initialize auto's with =, not {}.

  auto points = std::vector<Point>{{Point{1,1}, Point{1,2}, Point{-1,1}, Point{-2,2}}};
  auto diagonal_points = find_diagonal_points(points);
  for(auto p: diagonal_points)
    std::cout << p << std::endl;
}

int main () {
  without_auto();
  std::cout << std::endl;
  with_auto();
}

Program: Same - without std:: - with using namespace std. This example is not really important for the discussion of auto. It illustrates the burden of using fully quallified names with namespace prefix.
// Same as above, with a using directive for the std namespace. Actually it illustrates a bad use of a using directive.

#include <iostream>    
#include <vector>
#include <cmath>    // abs
#include "point.h"

using namespace std;   // In this variant, we do not qualify each name from the standard namespace with std::

// Illustration of alternative return type - best if return type depends on parameters.
auto find_diagonal_points(vector<Point> points) -> vector<Point>{
  vector<Point> res;
  for(auto p: points)
    if(abs(p.getx())==abs(p.gety()))
      res.push_back(p);
  return res;
}

void without_auto(){
  int i{5};

  vector<Point> points = {Point{1,1}, Point{1,2}, Point{-1,1}, Point{-2,2}};
  vector<Point> diagonal_points = find_diagonal_points(points);
  for(Point p: diagonal_points)
    cout << p << endl;
}

void with_auto(){
  auto i = 5;       // initialize auto's with =, not {}.

  auto points = vector<Point>{{Point{1,1}, Point{1,2}, Point{-1,1}, Point{-2,2}}};
  auto diagonal_points = find_diagonal_points(points);
  for(auto p: diagonal_points)
    cout << p << endl;
}

int main () {
  without_auto();
  cout << endl;
  with_auto();
}

Program: Same - illustrates deduction of a functions return type in C++14.
// C++14 - illustrates deduction of a functions return type.

#include <iostream>    
#include <vector>
#include <cmath>    // abs
#include "point.h"

// Illustration of deduction of a function's return type (C++14):
auto find_diagonal_points(std::vector<Point> points){
  using namespace std;

  vector<Point> res;
  for(auto p: points)
    if(abs(p.getx())==abs(p.gety()))
      res.push_back(p);
  return res;
}

Reference

Deduction of types with decltype
Slide Contents Index
References 

It is possible to decuce the type of an arbitrary expression with decltype

Reference
  • The C++ Prog. Lang. (4. edition): Page 165

Reference
  • Effective Modern C++: Understand decltype. Item 3

Program: Trivial uses of decltype.
// Trivial examples - not useful for practical purposes.

#include <iostream>
#include <vector>

int main(){
  double d1 = 5.5;
  std::vector<double> vd1{};  

  decltype(d1) d2 = 6.6;          // d2 is a double
  decltype(vd1) vd2{1.2, 3.4};    // vd2 is a vector

  int i = 7;
  decltype(d1+i) d3 = 7.7;        // d3 is a double

  // ...
}

Most real-life uses of decltype takes place in generic program - using templates

Reference

Program: A sample use of decltype in a function template: matrix plus.
// Illustrates that the return type of th plus function depends of the type of the sume of 'a T-value' and an 'U-value'.
// Compiles with g++ -c dt2.cc -std=c++11 
// The example comes from The C++ Language (4ed) page 165.

template<typename T> class Matrix;

template<typename T, typename U>
auto plus(const Matrix<T>& a, const Matrix<U>& b) -> Matrix<decltype(T{}+U{})>;

Program: Another sample use of decltype in a function template: container example.
// Illustrates that the return type of f may depend on the 'element type' of the container, more precisely by the type of c[i].
// For some container types, such as vector<bool>, the element type may be non-obvious.
// Compiles with g++ -c dt3.cc -std=c++11 
// The example is adapted from item 3 of Effective Modern C++.

template<typename Container, typename Index>
auto f(Container& c, Index i) -> decltype(c[i]){
  //...
}

Initialization
Slide Contents Index
References 

C++ supports several different notations and mechanisms for initialization

Reference
  • The C++ Prog. Lang. (4. edition): Page 159

Reference
  • Effective Modern C++: Distinguish between () and {} when creating objects. Item 7

Program: Four forms of initialization.
  T v1 = v;    // C style initialization.
  T v2 = {v};  // C style List initialization.
  T v3(v);     // Constructor style initialization.
  T v4{v};     // Universal initialization, without narrowing. Preferred.
  T v5{};      // Default initialization. For user-defined types, use parameterless constructor.

References

  • New style universal initialization - with {}

    • Can be used (almost) everywhere

    • Generalizes the notation used for initialization of arrays and structs in C

    • Can also be used for passing parameters to constructors

      • Although with some ambiguities, forcing the use of old-style initialization (!!)

Initialization examples
Slide Contents Index
References 

We show examples of default initialization, initialization without narrowing with {}, and initialization with auto

Program: Default initialization.
// Shows default initialization with {}

#include <iostream>

class Point {
public:
  double x, y;
  Point(double x, double y): x(x), y(y) {}
  Point(): x(1.1), y(2.2){}
};

int f(){
  int i{};     // i becomes 0, the default int value
  double d{};  // d becomes 0.0, the default double value
  char *c{};   // c becomes the null pointer, the default pointer value
  Point p{};   // p becomes (1.1, 2.2), the default Point object - using the default constructor

  std::cout << "i: " << i << std::endl;                                // 0
  std::cout << "d: " << d << std::endl;                                // 0
  std::cout <<  std::hex << "c: " << (unsigned int)c << std::endl;     // 0
  std::cout << "p: " << p.x << ", " << p.y << std::endl;               // 1.1, 1.2
}

int main(){
  f();
}

Program: Initialization and narrowing.
// Shows initialization with and without narrowing. Initialization with {} prohibits narrowing (causes warnings).

#include <iostream>
#include <string>

void f(double dval, int ival){
  int i = dval;    // OK - narrowing conversion to int, and initialization 
  char ch = ival;  // OK - narrowing conversion to char (skipping higher order bits) and initialization 

  std::cout << "i: " << i << std::endl;     // 3
  std::cout << "ch: " << ch << std::endl;   // L 
}

void g(double dval, int ival){
  int i {dval};     // warning: narrowing conversion ...
  char ch {ival};   // warning: narrowing conversion ...

  std::cout << "i: " << i << std::endl;     // 3
  std::cout << "ch: " << ch << std::endl;   // L
}

int main(){
 f(3.1415, 1100); 
 g(3.1415, 1100); 
}

Program: Initialization and auto - problems.
// Shows initialization together with auto.
// Best to use = for initialization of variables of auto type.
// Problems in this example.

#include <iostream>

void f(){
  auto x {101};  // x is an object of type initializer_list<int>: A list with a single element.

  // problems here... Does not compile.
  std::cout << "x: " << x << std::endl;   

  // OK - x is a list:
  for(auto element: x){std::cout << element;};   // 101
}

int main(){
  f(); 
}

Program: Initialization and auto - OK.
// Illustrates initialization and auto.
// Best to use = for initialization of variables of auto type.
// This example is OK.

#include <iostream>

void f(){
  auto x = 101;  // x is an int

  std::cout << "x: " << x << std::endl;   // OK:  x: 101
}

int main(){
  f(); 
}

Program: Initialization - ambiguities.
// Illustrates ambiguities in certain initializations.

#include <iostream>
#include <string>
#include <vector>

int main(){
  using std::vector;
  using std::string;

  // A trap:
  vector<int> v1{99};     // A vector with single int element, with value 99 - prefer list initialization
  vector<int> v2(99);     // A vector of 99 ints with default value 0 - forces use of a Vector constructor

  // As expected:
  vector<string> v3{"hello"};   // A vector with single string element "hello"
  vector<string> v4("hello");   // ERROR: There is no vector constructor with a single string parameter

  for(auto x: v1) std::cout << x << std::endl;  // 99
  for(auto x: v2) std::cout << x << std::endl;  // 0 0 ... 0   (99 zeros)
  for(auto x: v3) std::cout << x << std::endl;  // hello

}

C++ ISSUE: Constness
Slide Contents Index
References 

On this page we care about problems - and we ask more questions than we provide answers

  • Literals in relation to constants?

  • Constants in relation to compile time computations?

  • What is the basic idea behind constant variables?

  • Is const part of a C++ type?

  • What is a const function (good for)?

  • Constant pointers? Constant references?

  • What is the justification of const casting?

Reference

Constants
Slide Contents Index
References 
Intern kommentar til forelæsningen om denne slide:
Vær sikker på at få detaljerne helt på plads i programmet. Ikke mindst de to (dobbelt) erklæringer af w, hvor Point const og const Point er ækvivalente.

The const qualifier can be used in several different contexts in C++

Constness is a fairly complicated matter in C++

Reference
  • The C++ Prog. Lang. (3. edition): Page 94 - 97

Reference
  • The C++ Prog. Lang. (4. edition): Page 186

  • The basics

    • The const qualifier can be applied to objects, types, and member functions

    • Constant objects cannot be mutated

  • Pointers and const

    • Either a constant pointer or a pointer to something constant

      • this is a constant pointer

    • *const is declarator operator - constant pointer

      • Other declarator operators: *, [], and ()

Reference

  • References and const

    • By nature a reference is constant - once the reference is establised it cannot be changed

  • Member functions and const

    • A constant member function cannot modify the state of the object

Program: Examles constants, pointers to constants, and constant pointers.
// Illustrates constness, in particular in relation to pointers. DOES NOT COMPILE.

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

int main(){
  Point p(1,2);             // p is a Point. It can be moved (by mutation).
  p.move(0,1);

  const Point q(3,4);       // q is a constant point.
  q.move(1,2);              // ERROR (compile time)

  const Point *r = &p;      // r is pointer to a constant point
  r->move(1,2);             // ERROR (compile time)

  Point const *rr = &p;     // rr is pointer to a constant Point - fully equivalent to definition or r above.

  Point *const s = &p;      // s is a constant pointer to 'the point p'. *const is a 'declarator operator'.
  s->move(1,2);             // OK.
  s = nullptr;              // ERROR: Assignment of read-only variable s. (Compile time)

  const Point *const t= &p; // t is a constant pointer to a constant point.
  t->move(1,2);             // ERROR (compile time)
  t = nullptr;              // ERROR (compile time)

  Point const *const v= &p; // Same as definition of t (Point and const has just been reversed). 
}

Program: Only the valid parts of the program from above - compiles. Intern kommentar til forelæsningen om denne slide:
Do not spend time on this during the lecture
// Compilable parts of previous program.

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

int main(){
  Point p(1,2);             // p is a Point. It can be moved (by mutation).
  p.move(0,1);

  const Point q(3,4);       // q is a constant point.

  const Point *r = &p;      // r is pointer to a constant point

  Point const *rr = &p;     // rr is pointer to a constant point - fully equivalent to definition or r above.

  Point *const s = &p;      // s is a constant pointer to 'the point p'. *const is a 'declarator operator'.
  s->move(1,2);             // OK.

  Point const* w = &p;      // w is a pointer to a constant point.  const* is NOT a 'declarator operator'.
                            // Point const ...  and  const Point means the same.

  const Point *const t= &p; // t is a constant pointer to a constant point.

  Point const *const v= &p; // Same as definition of t (Point and const has just been reversed). 
}

Program: point.h - just for reference. Intern kommentar til forelæsningen om denne slide:
Don't go into this...
// Just for reference - not really interesting in this context.

class Point {
private: 
  double x, y;

public:
  Point(double, double);
  Point();
  double getx () const;
  double gety () const;
  void move(double, double);
  double distance_to(Point);
};

std::ostream& operator<<(std::ostream&, const Point&);

Program: point.cc - just for reference.
// Just for reference - not really interesting in this context.

#include <cmath>
#include <iostream>
#include "point.h"

Point::Point(double x_coord, double y_coord): x(x_coord), y(y_coord){
}

Point::Point(): x(0.0), y(0.0){
}

double Point::getx () const{
  return x;
}

double Point::gety () const{
  return y;
}

void Point::move(double dx, double dy){
    x += dx; y += dy;
}

double Point::distance_to(Point p){
    return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
}

std::ostream& operator<<(std::ostream& s, const Point& p){
  return s << "(" << p.getx() << "," << p.gety() << ")" ;
}

Point Exercise - C++ versus C#
Slide Contents Index
References 

This slide contains programs intended for an exercise about similarities and differences between C++ / C# object allocation, access, and parameter passing

Program: The C# Point class.
using System;

public class Point {
  private double x, y;

  public Point(double x, double y){
   this.x = x; this.y = y;
  }

  public double Getx (){
    return x;
  }

  public double Gety (){
    return y;
  }

  public void Move(double dx, double dy){
    x += dx; y += dy;
  }

  public double DistanceTo(Point p){
    return Math.Sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
  }

  public override string ToString(){
    return "Point: " + "(" + x + ", " + y + ")" + ". ";
  }
}

Program: A C# client class of class Point.
using System;

public class PointClient{

  public static void Main(){
    PointClient pc = new PointClient();
    pc.Go();
  }

  public void Go(){
    Point p1 = new Point(1, 2),
          p2 = new Point(3, 4),
          p3 = p1,
          p4 = p2,
          p5;

    p5 = PointMover(p1, p2);

    Console.WriteLine("{0} {1} {2} {3} {4}", 
       p1, 
       p2, 
       p3, 
       p4, 
       p5  
     );
  }

  public Point PointMover(Point pa, Point pb){
    pa.Move(5,6);
    pb.Move(-5,-6);
    return pb;
  }

}

Program: A C# client class of class Point - with comments that reveal the output.
using System;

public class PointClient{

  public static void Main(){
    PointClient pc = new PointClient();
    pc.Go();
  }

  public void Go(){
    Point p1 = new Point(1, 2),
          p2 = new Point(3, 4),
          p3 = p1,
          p4 = p2,
          p5;

    p5 = PointMover(p1, p2);

    Console.WriteLine("{0} {1} {2} {3} {4}", 
       p1,  // (6,8)
       p2,  // (-2,-2)
       p3,  // (6,8)      an alias of p1
       p4,  // (-2,-2)    an alias of p2
       p5   // (-2,-2)    another alias of p2
     );
  }

  public Point PointMover(Point pa, Point pb){
    pa.Move(5,6);
    pb.Move(-5,-6);
    return pb;
  }

}

Exercise 2.4. Contrasting use of C# and C++ classes: Class Point

In this exercises we will explore some basic similarities and differences between use of classes in Java/C# and C++. (In the scope of this lecture we will NOT be concerned with class definition details. This belongs to a forthcoming lecture). In particular we will study creation/allocation of objects, and parameter passing of objects to a function/method.

The starting point is the simple Point class in C# and a sample C# client program that creates and operates on points. On purpose, I do not use C# properties - but simple accessor methods (ala Java). Make sure that you familiarize yourself with the correct output of this program. Predict it before you run it.

We provide a similar Point class in C++. The C++ definitions of the Point functions are also provided (but they are not important for this exercise). You are supposed to explore various uses of class Point in C++.

  1. Write a C++ client program that corresponds as close as possible to the C# client program. In this version of the C++ program you should access Point objects via pointers to objects on the free store (the heap). You may want to read a bit about the free store and new in C++.
  2. Adjust the program such that the Point objects are allocated on the stack, and accessed via pointers (Use the address operator to get the pointers). Does this affect the need for deallocation?
  3. Write another version of the C++ client program that uses C++ references instead of pointers. The goal is to come as close as possible to the pointer-based program you wrote above.
  4. Finally, write a C++ client program that use pure and simple value semantics of points. In other words, do not use references nor pointers at all in this version of the C++ program. We accept that the meaning of the program changes due to the introduction of value semantics. Predict the output of the program before you run it.

Feel free to do other experiments based on the Point classes that help you understand the similarities and differences between use of C# and C++ classes, pointers, references, and stack allocation of C++ objects.


Collected references
Contents Index
Basic facilities in the next lecture
Fundamental types in C
The C++ Prog. Lang. (3. edition): Page 71
The C++ Prog. Lang. (4. edition): Page 139
The C++ Prog. Lang. (3. edition): Page 234
The C++ Prog. Lang. (4. edition): Page 47, 454
Structs in C
The C++ Prog. Lang. (3. edition): Page 78
The C++ Prog. Lang. (4. edition): Page 152
The C++ Prog. Lang. (3. edition): ODR. Page 203
The C++ Prog. Lang. (3. edition): Page 79 - 80
The C++ Prog. Lang. (4. edition): Page 153
The C++ Prog. Lang. (3. edition): Page 80
The C++ Prog. Lang. (4. edition): Page 154
The C++ Prog. Lang. (3. edition): Page 133, 135
The C++ Prog. Lang. (4. edition): Page 227
The C++ Prog. Lang. (3. edition): Page 84
The C++ Prog. Lang. (4. edition): Page 165-166
Objects - instances of classes
The C++ Prog. Lang. (4. edition): Page 166
Objects
Pointers
The C++ Prog. Lang. (3. edition): Page 97
The C++ Prog. Lang. (4. edition): Page 189
The C++ Prog. Lang. (3. edition): Argument passing. Value return. Page 145-148
The C++ Prog. Lang. (4. edition): Argument passing. Page 316-318
The C++ Prog. Lang. (4. edition): Value return. Page 310
C#: Ref parameters
The C++ Prog. Lang. (3. edition): Page 146
The C++ Prog. Lang. (4. edition): Page 316
The C++ Prog. Lang. (3. edition): Page 98, 146, 148, 283
The C++ Prog. Lang. (4. edition): Page 191
Rvalues
Lvalue references
The C++ Prog. Lang. (4. edition): Page 193
Rvalues and move constructors
The C++ Prog. Lang. (3. edition): Page 148
The C++ Prog. Lang. (4. edition): Value return. Page 308
The C++ Prog. Lang. (4. edition): Page 190, 193
The C++ Prog. Lang. (4. edition): Page 193-195
The C++ Prog. Lang. (4. edition): Page 163, 308
Effective Modern C++: auto type deduction. Item 2
Initialization with auto
The C++ Prog. Lang. (4. edition): Page 165
Effective Modern C++: Understand decltype. Item 3
Templates
The C++ Prog. Lang. (4. edition): Page 159
Effective Modern C++: Distinguish between () and {} when creating objects. Item 7
Struct initialization in C
Array initialization in C
constexpr
The C++ Prog. Lang. (3. edition): Page 94 - 97
The C++ Prog. Lang. (4. edition): Page 186
References

 

Chapter 2: Basic facilities, Part 1
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: August 1, 2017, 13:25:38