CISC 3142
Programming Paradigms in C++
Preliminaries

A review and examination of the following Java topics and concepts will ease the transition to programming in C++, as well as hopefully clearing things in Java as well

Java Compilation / Interpretation vs C++ Compilation / Linking / Execution

Java

C++

Scope and Lifetime

Scope

Java

C++

Lifetime (allocation / storage duration)

Java

C++

Categories of values, objects, variables

Java

C++

Reference and Value-semantics

Does assignment involve copying the object's reference (reference semantics) or its value (value semantics)?

Aliases vs Copies

Java

Copy Constructors and Copy Methods in Java

class Integer {
	Integer(int val) {this.val = val;}
	Integer(Integer integer) {val = integer.val;}	// copy constructor
	…
	void copy(Integer integer) {val = integer.val;}	// in-place copy method
	…
	int val;
}
…
Integer i1 = new Integer(3);		// uses 'int' constructor
Integer i2 = new Integer(12);		// uses 'int' constructor
Integer i3 = new Integer(i1);		// uses copy constructor — clone
Integer i4 = i1;			// reference assignment — alias
i2.copy(i3);				// in-place copy method — clone
i2 = new Integer(i4);			// copy constructor — clone

Other Flavors of Copy Methods in Java

C++

Parameter transmission

Basic Terminology

The caller passes arguments to the method where they are received in parameters

Call-by-Value

Java

The Problem with Swapping Two Values in Java

Swapping in Java

Using an Array
static void swap(int [] arr, int index1, int index2) {	
	int t = arr[index1];
	arr[index1] = arr[index2];
	arr[index2] = t;
}

in this scenario, we are not modifying the parameters — in particular the array reference — but rather elements of the object (i.e., the array) it references

Embedding the Values to be Swapped in an Object
class Pair {
	Pair(int first, int second) {
		this.first = first;
		this.second = second;
	}
	public int first, second;	// making them public so we can get to them - not relevant to the discussion
}

Pair pair = new Pair(a, b);
swap(pair);
a = p.first;
b = p.second;	

static void swap(Pair p) {	
	int t = p.first;
	p.first - p.second;
	p.second = t;
}

again, we are not modifying the parameter (the object reference), but rather what it is referencing — instance variables of the object (i.e., the Pair) it references

Objects and Arrays May be Changed, but It's still Call-By-value

int [] arr = {1, 2, 3};
inc(a);
…
void inc(int [] arr) {
	for i in 0; i < arr.length; i++)
	arr[i]++;
}

A Common Mistake: Modifying the Value of a Reference Parameter
The effect of modifying an object via indirection through a reference parameter is often mistaken (and referred to) as call-by-reference. There are probably two reasons for this: While it's true that the reference parameter is what supplies the indirection and thus the modification of the object, the reference itself is what is being passed and THAT is still being passed by-value (i.e., as a copy of the argument).
int [] arr = {1, 2, 3};
resize(a);
…
void resize(int [] arr) {
	int [] temp = new int [arr.length * 2];
	for (int i = 0; i < arr.length; i++)
		temp[i] = arr[i];
	arr = temp;
}

C++

Generics

generic programming

Java

C++

vector<int> i_vect;
i_vect.add(12);
…
vector<string> s_vect;
s_vect.add("Hello");
				

Polymorphism

Overloading and Overriding

overloading (compile time / static polymorphism) vs. overriding (run time / dynamic polymorphism)

Overloading (Compile-time Polymorphism)

Methods can be defined with the same name (in the same scope) as long as they differ by number and/or types of parameters.
class C {
	…
	void print(int i) {…}
	void print(String s) {…}
	…
}

Overriding (Run-time Polymorphsim)

Methods within a subclass can be defined with the same name and type signature as a method in a superclass; the subclass method will be invoked when messages are passed to a subclass object (even if through a superclass variable).
class C {
	…
	void f(int i) {…}
	…
}
…
class D extends C {
	…
	void f(int i) {…}
	…
}

Immutable vs Mutable

Maintaining Semantic Consistency

Semantic consistency: logically related concepts should should have the same meaning / treated the same way. We can achieve semantic consistency across methods, by being disciplined in our coding. The most common way to do this is by having methods that should be semantically consistent share code. This is done by leveraging functionality

Leveraging Functionality

Delegation / Wrapper Methods

Example: size and isEmpty

Example: Composition of toString Methods

Example: Copy Constructors and Copy Methods

!!! Needs picture!!!

Example: Immutable and Mutable Arithmetic Operators

A Related Example: Mutable and Immutable Methods of a Rational Class

rational number: a number that can be represented as the ratio of two integers; i.e., a number that can be represented using a numerator and denominator; a fraction.
class Rational {
	…
	Rational mul(Rational r) {…}		
	Rational mulInPlace(Rational r) {…}
	…
	int num, denom;
}
Rational 
	r1 = new Rational(1, 2),
	r2 = new Rational(3, 4);

Rational r3 = r1.mul(r2);	// r3 is pointing at a new Rational containing 3/8; r1 and r2 are unchanged
r1.mulInPlace(r2);		// r1 is still pointing at the same object as before, but the num/denom is now 3/8
r2 = r2.mul(r2);		// r2 is pointing at a new (different) Rational object containing 9/16

Deciding on Who Leverages Whom

Sometimes one has no choice: However, one often has a choice as to which function is leveraged (i.e., which is the workhorse and which the wrapper):

Example: The Rational class again

The semantics of rational number multiplication is to multiply the numerators and denominators, i.e.,
a     c     a * c
-  *  -  =  -----
b     d     b * d
No Leveraging
I.e., both methods perform the multiplication logic … this 'no leveraging example' is just for illustrative purposes; typically one method would leverage the other, as shown in the next two sections.
mul Method
Rational mul(Rational r) {
	Rational result = new Rational(this.num * r.num, this.denom * r.denom);
	return result;
}
mulInPlace Method
Rational mulInPlace(Rational r) {
	this.num *= r.num;		
	this.denom *= r.denom;
	return this;
}
mulInPlace Leveraging mul
mul Leveraging mulInPlace
More on mulInPlace's Return Value

Initialization of Variables in the Presence of Composition and Inheritance

General Philosophy

Java

C++

Composition

Java

C++

Inheritance

Java

C++

Code Used in this Lecture