Fall 2013
CS2150: Program and Data Representation University of Virginia Computer Science
Aaron Bloomfield and Mark Floryan
C++
Intro to C++
Why C++ and not Java?
Its good to learn a second language C++ is widely used
Can be more efficient More control
C++ will let us get under the hood more
Data and program representation in memory Memory allocation
3
A brief history lesson
C was created in 1972 by Dennis Ritchie
Intended to be terse, quick to write, and efficient
C++ was created in 1985 by Bjarne Stroustrup
Added classes while being backwards compatible Has pretty terrible syntax!
4
Hello World Java vs. C++
// Java public class HelloWorld { public static void main(String [] args) { System.out.println("Hello World!"); } } // C++ #include <iostream> using namespace std; int main() { cout << Hello World! << endl; return 0; }
5
Differences
main() Preprocessor
#include
using namespace std; Output
main()
Not a part of any class
called a function
Must be global Must have a return type of int
By convention, main returns 0
Preprocessor
Examples
#include <iostream> // System file #include ListNode.h // user-defined file
What this does
Compiler inserts the contents of the file in the place where the #include statement appears
C++ Compilation Process Overview
1. Preprocess source file
handle #includes and any other # statements
2. Compile resulting file 3. Link the resulting files from Step 2 (more on this later)
using Directive
Similar to Javas import
Allows the programmer to not have to type the full class name
// C++ #include <iostream> using namespace std; int main() { cout << Hello World! << endl; return 0; } // C++ #include <iostream> int main() { std::cout << Hello World! << std::endl; return 0; }
10
I/O
Basic I/O
// use iostream library #include <iostream> using namespace std; int main() { int x; cout << Enter a value for x: ; cin >> x; return 0; }
11
C++ Primitive Types
int
Can be 16, 32, 64 bits depending on the platform
float double char
C++ generally uses 8 bit ASCII encoding (more on this later)
bool
12
C++ Operators and Expressions
if statement
in C++ condition can be either int or bool if ( x = 0 )
This will NOT cause a compiler error in C++
if ( i )
This is valid
13
Operators and Expressions
loops, same as Java
while, for, do while, break, continue
14
Compiler choice
In the past we have used g++
From GNUs Compiler Collection
We are now using clang (from LLVM)
It has MUCH better error messages
Consider:
speling mistake!
#include <iostream> using namespace std; int main() { cotut << "Hello World"; return 0; }
15
g++:
Error comparison
clang:
16
Functions
Functions
Methods not member of a class
#include <iostream> using namespace std; ret_type func_name(int a, int b, ) { <function body> } int main() { z = func_name(x,y, ) return 0;}
18
Declaring mutually recursive functions
bool even (int x); bool odd (int x) { if ( x == 0 ) return false; else return even (x-1); } bool even (int x) { if ( x == 0 ) return true; else return odd (x-1); }
19
Function Prototypes
C++ compiler process files top to bottom
order of appearance matters without a function prototype
General form of a prototype
ret_type func_name(int a, int b, );
20
#include <iostream> using namespace std;
Example
// prototype
int max(int a, int b);
int main(){ int x=37; int y=52; cout << max(x,y) << endl; return 0; } // actual function implementation int max(int a, int b) { return (a>b) ? a : b; }
21
Classes
Java IntCell.java
public class IntCell { public IntCell() // default constructor { this(0); } // one parameter constructor public IntCell(int initialValue) { storedValue = initialValue; } // accessor member function public int getValue() { return storedValue; } // mutator member function public void setValue(int val) { storedValue = val; }
(continued on next slide)
23
Java IntCell.java
// private data member private int storedValue; // main() public static void main(String [] args) { IntCell m1 = new IntCell(); IntCell m2 = new IntCell(37); System.out.println(m1.getValue() + + m2.getValue()); } }
24
How Would You Translate This Java Source into C++?
Need 3 files
1. Header file that contains class definition Separation of interface
IntCell.h and implementation
2. C++ file that contains class implementation
IntCell.cpp
3. C++ file that contains a main()
TestIntCell.cpp
25
C++ IntCell TestIntCell.cpp
#include <iostream> #include "IntCell.h" using namespace std; int main( ) { IntCell m1; // calls the default constructor IntCell m2( 37 ); //IntCell m2 = 37; // does not work cout << m1.getValue( ) << " " << m2.getValue( ) << endl; m1 = m2; m2.setValue( 40 ); cout << m1.getValue( ) << " " << m2.getValue( ) << endl; return 0; }
26
C++ IntCell IntCell.h
#ifndef INTCELL_H #define INTCELL_H
No visibility modifier class IntCell { public: explicit IntCell( int initialValue = 0 );
int getValue( ) const; void setValue( int val ); private: int storedValue; int max(int m); }; semi-colon ends #endif class declaration
27
C++ IntCell IntCell.cpp
#include "IntCell.h" IntCell::IntCell( int initialValue ) : storedValue( initialValue ) { }
explicit not present
int IntCell::getValue( ) const { return storedValue; } void IntCell::setValue( int val ) { storedValue = val; } int IntCell::max(int m){ return 1; }
28
C++ IntCell IntCell.h (again)
#ifndef INTCELL_H #define INTCELL_H class IntCell { public: explicit IntCell( int initialValue = 0 ); int getValue( ) const; void setValue( int val ); private: int storedValue; int max(int m); }; #endif
29
C++ IntCell TestIntCell.cpp
#include <iostream> #include "IntCell.h" using namespace std; int main( ) { IntCell m1; // calls the default constructor IntCell m2( 37 ); //IntCell m2 = 37; // does not work cout << m1.getValue( ) << " " << m2.getValue( ) << endl; m1 = m2; m2.setValue( 40 ); cout << m1.getValue( ) << " " << m2.getValue( ) << endl; return 0; }
30
Separate Compilation
Java source
Java Compiler
C++ source files Preprocessor
preprocessed files
Java bytecode ( .class file)
Compiler
object files
JVM
Machine language
Linker
executable file
Machine language
31
In-Class Example (Files on Collab)
Converting Java to C++ Rational.java to Rational.h Rational.cpp TestRational.cpp
The General Conversion Process
1. Create .h file with class definition
Member function signatures, no implementations
2. Create .cpp file containing member function implementations 3. Create .cpp file containing main()
33
Reminders
1. int main() 2. Input/Output
#include <iostream> using namespace std; cout << varName << << endl;
3. Class syntax
public and private sections semi-colon at the end of class declaration ClassName::
34
Ill Explain Later, But For Now
1. Printing
instead of + use << to concatenate items to print
2. Remove this and new from conversion
35
#ifndef RATIONAL_H #define RATIONAL_H class Rational { public: Rational(); // default constructor ~Rational(); // destructor Rational(int numerator, int denominator); void print() ; Rational times(Rational b); Rational plus(Rational b); Rational reciprocal(); Rational divides(Rational b); private: int num; // the numerator int den; // the denominator int gcd(int m, int n); }; #endif
Rational.h
36
Rational.cpp
#include "Rational.h" #include <iostream> using namespace std; // default constructor: initialize to 0/1 Rational::Rational() : num(0), den(1) { } void Rational::print() { if (den == 1) { cout << num << "" << endl; } else { cout << num << "/" << den << endl; } }
37
Rational.cpp
Rational Rational::times(Rational b) { return Rational(num * b.num, den * b.den); }
38
Rational.cpp
Rational::Rational(int numerator, int denominator) { if (denominator == 0) { cout << "Denominator is zero" << endl; } int g = gcd(numerator, denominator); num = numerator / g; den = denominator / g; }
39
TestRational.cpp
#include "Rational.h" int main() { Rational x, y, z; // 1/2 + 1/3 = 5/6 x = Rational(1, 2); y = Rational(1, 3); z = x.plus(y); z.print(); // other code very much like above }
40
.h vs. .cpp?
C++ naming convention
.h // header files
function prototypes class definitions macro definitions
.cpp // implementation files
Definitions may only appear in 1 place
compiler errors: multiply defined XYZ
41
Pre-processor
Preprocessing
#include
Direct copy of file specified to location specified In general, only #include .h files.
#ifndef
if not defined other preprocessor directives: #ifdef, #if
#define
Defines a macro (direct text replacement) #define TRUE 0 if(TRUE == 0) {} #define _MY_OBJECT_H
#endif
specifies the end of any #if
43
#define
Can define a constant
#define PI 3.14159 area = PI * r * r;
Can just define an identifier
#define FOO #ifdef FOO #ifndef FOO // is true! // is false!
44
What problems arise?
odd.h:
#include even.h bool odd (int x);
even.h:
#include odd.h bool even (int x);
45
Preventing #include loops
odd.h:
#ifndef ODD_H #define ODD_H #include even.h bool odd (int x); #endif
even.h:
#ifndef EVEN_H #define EVEN_H #include odd.h bool even (int x); #endif
46
Pointers
Pointer Variables
Stores a memory address of another object
Can be a primitive type or a class type
48
Examples of Pointers
int * x; // pointer to int char *y; // pointer to char Rational * rPointer; // pointer to Rational
49
What Types are These?
1. 2. 3. 4. 5. float * num1 double num2 Rational fraction1 Square * square1 int num3
50
C++ Syntax: *
Asterisk *
In a definition
defines pointer type
int *x
In an expression
dereferences evaluates object to which the pointer points
*x = 2
51
C++ Syntax: &
Ampersand &
In a definition
defines a reference type (more on this later)
In an expression
address of
x = &y
52
Pointer Variables
x
Address 1000 1 int x = 1; int y = 5; int * x_pointer = &x; cout << x_pointer; cout << *x_pointer;
1004
1008 1012 1016
1000
type pointer to int
x_pointer
53
x_pointer = &x
address
* dereferences x_pointer
54
Dereferencing and Assigning
Address x 12FF60 y 12FF54 12FF 12FF Dereference x_pointer 1 5 2
*x_pointer = 2;
12FF x_pointer
12FF60
55
*x_pointer = 2
56
x_pointer = &y
Address x 12FF60 y 12FF54 2 5
x_pointer = &y;
address of
12FF
12FF 12FF x_pointer
12FF60 12FF54
57
x_pointer = &y
58
*x_pointer = 3
Address x 12FF60 y 12FF54 2 5 3
*x_pointer = 3;
dereference x_pointer
12FF
12FF 12FF x_pointer
12FF54
59
Binkys Pointer Fun
cslibrary.stanford.edu
Binkys Pointer Fun
http://www.youtube.com/watch?v=UvoHwFvAvQE
61
What Types are These?
1. 2. 3. 4. char * x; int **y; Rational *rNumber1; Square **blah;
62
Pointer Pitfalls: Uninitialized Pointers
Cause runtime errors
int n = 30; int * p; *p = n; //ERROR!!!
p does not have a valid memory address! A common initializer value used by programmers is NULL int *p=NULL; // better code, then add code to check for NULL value
63
Uses for Pointers
swap()
void swap(int * x, int * y) { int temp = *x; *x = *y; *y = temp; }
65
Calling swap()
int main() { int a=0; int b=3; cout << "Before swap(): a: " << a << "b: " << b << endl; swap(&b,&a); cout << "After swap(): a: " << a << "b: " << b << endl; return 0; }
66
Dynamic Memory Allocation
new and delete
Static Memory Allocation
Amount of space (memory) already known
// declare array of 10 elements int someArray[10]; // declare a pointer to int int *value1_address = someArray[3];
68
Dynamic Memory Allocation
Dont know how much memory is needed in advance Need to create the space on the fly new
returns a pointer to newly created thing
69
Dynamic Arrays
int main() { int n; // read in a value from the user cout << "Please enter an integer value: " ; cin >> n; // use the user's input to create an array of int using new int * ages = new int [n];
70
// use a loop to prompt the user for (int i=0; i < n; i++) { cout << "Enter a value for cin >> ages[i]; } // print out the contents of the for(int i=0; i<n; i++) { cout << "ages[ " << i << " }
to initialize the array
ages[ " << i << " ]: ";
array
]: " << ages[i];
// finished with the array //clean up the memory used by calling delete delete [] ages; return 0; }
71
Output
72
C++ Syntax: new
General form
SomeTypePtr = new SomeType; Examples
int * intPointer = new int; Rational * rPointer = new Rational; int * intPointer2 = new int(0); Rational * rPointer2 = new Rational(1,2);
73
Memory Management
Java is garbage collected
Allocated memory is automatically reclaimed, programmer does not need to think about it
C++ does not have garbage collection
Programmer must reclaim that memory, otherwise that memory cant be used
74
C++ Syntax -- delete
delete
delete rPointer delete intPointer
delete []
delete [] ages
75
delete
#include <string> using namespace std; int main() { string * pointerToString = new string(hi); // some code that uses pointerToString here delete pointerToString; return 0; }
76
Remember this
Anything allocated with new MUST be deallocated with delete
77
Accessing parts of an object
For a regular (i.e., non-pointer) object, use a period:
Rational r; r.num = 4;
For a pointer, dereference it first (as *r is the object, and r is the pointer):
Rational *r = new Rational(); (*r).num = 4;
A shorthand for the last line is below (the arrow means follow the pointer):
r->num = 4;
References (which we havent seen yet) work like regular objects
78
C++ and memory allocation
Assume int *x has been declared
And int y is from user input
Consider these separate C++ lines of code:
x = new int[10]; x = new int; x = new int[y]; // 40 bytes // 4 bytes // y*4 bytes
When they are deleted, how does C++ know how much memory to free up?
79
#include <iostream> using namespace std; class Foo { int x, y; };
C++ and memory allocation
int main() { cout << "sizeof(int): " << sizeof(int) << endl; cout << "sizeof(Foo): " << sizeof(Foo) << endl; Foo *foo = new Foo(); Foo *bar = new Foo(); cout << "1st Foo: " << foo << endl; cout << "2nd Foo: " << bar << endl; int diff = ((int)bar)-((int)foo); cout << "Difference: " << diff << endl; delete foo; delete bar; return 0;
sizeof(int): 4 sizeof(Foo): 8 1st Foo: 0x6a0670 2nd Foo: 0x6a0680 Difference: 16
80
Associativity of *
Consider:
char* x, y;
We can all agree that x is a character pointer (32 bits) But what type is y?
Its a regular char (8 bits)
The * is right associative, meaning that the spacing should be:
char *x, y;
This wont be consistent in this course
81
Doubly linked lists
A very brief overview
From lab 2
83
friend
Sometimes other classes need access to private data members of another class class ListNode { Why not just write accessor functions? public: // private: ListNode *next, *previous;
friend class List;
};
84
Common mistakes
Consider a class Foo with an uninitialized ListNode* field list that needs to be initialized in the constructor. What is wrong with the following two methods?
They both compile just fine
Foo() { ListNode* list = new ListNode(); }
Foo() { ListNode temp; list = &temp; }
85
References
References
Declaring a reference
List sampleList List & theList = sampleList;
Reference to a List object What is a reference?
Like a pointer, it holds an address, BUT 1. Its address cannot change (its address is constant) 2. It MUST be initialized upon declaration (cannot be initialized to NULL normally) 3. Has implicit dereferencing int *x = NULL; int &y = *x;
87
swap() with Pointers
void swap(int * x, int * y) { int temp = *x; *x = *y; *y = temp; }
Programmer must specify dereferencing explicitly
88
swap with References
void { int x = y = } swap(int & x, int & y) temp = x; y; temp;
Dereferencing is implied with each use All Java non-primitive types are references
89
Calling swap() with references
int main() { int a=0; int b=3; cout << "Before swap(): a: " << a << "b: " << b << endl; swap(b,a); cout << "After swap(): a: " << a << "b: " << b << endl; return 0; }
90
Accessing Members of An Object
class Square { public: // constructors, etc. would be here int sideLength; };
91
Accessing Members through a Pointer
// other code omitted for space reasons int main() { Square *squarePtr = new Square(1); int length = squarePtr->sideLength; return 0; }
Equivalent to saying (*squarePtr).sideLength
92
Accessing Members through a Reference
// other code omitted for space reasons int main() { Square square = Square(1); Square & squareRef = square; int length = squareRef.sideLength; return 0; } Uses a period
93
Accessing Pointers within Objects
class example1 { public: int *a; }; example1 *c = new example1; int x = 0; Assign address of x (*c).a = &x c->a = &x;
dereference c, then access a
94
Pointer/Reference Cheat Sheet
Location
Definition
*
pointer to
&
reference to
Statement dereference
o1->method()
address of
is the same as (*o1).method()
95
Parameter Passing
Call By Value
Actual argument is copied into formal parameter int max(int a, int b); void swap (int * x, int *y); bool compare(Rational left, Rational right);
Can also pass pointers by value
97
Call By Reference
Pass references as parameters void swap (int &x, int &y);
Use when formal parameter should be able to change the value of the actual argument
98
Call By Constant Reference
Parameters are constant (wont change) and are passed by reference bool compare(const Rational & left, const Rational & right); Use when there is a class type that cannot be changed by formal parameter
99
Other parameter passing types
Call Call Call Call by by by by copy-restore name need macro expansion
100
Return Passing
Return by value
return a copy (possibly a copy of the pointer)
Return by reference
return a reference
Return by constant reference
101
Review
Review
Dynamic Memory Allocation
new
Allocates a new memory location for use Example:
Square * ptrToAnotherSquare = new Square(5); Triangle *ptrToTriangle = new Triangle(); Circle *ptrToCircle = new Circle;
delete
Reclaims memory allocated with new Example:
delete ptrToAnotherSquare;
Reclaims the memory location that was allocated, NOT the pointer. The pointer may be reassigned
103
Review
Call by value
actual argument is copied into formal parameter Example: int max(int x, int y); Use when parameters Call by reference wont need Passes references to change Example:
void swap(int & a, int & b){/* body */} int main() Function needs { to be able to int x = 1; change actual int y = 2; argument swap(x, y); // passed by reference return 0; }
104
Review
Call by constant reference
Passes references where function may not change the actual arguments Example:
bool greaterThan(const Rational & a, const Rational & b); Use for large int main() objects where { no changes will Rational x(1,2); occur. Rational y(3,4); Saves copy time bool result = greaterThan(x,y); and space. return 0; }
105
The Big Three
Destructors, Copy Constructors, operator=
C++ Provides These By Default
Destructor Copy Constructor operator=
There are some problems with these
107
Destructors
Called whenever an object
goes out of scope, or delete is called
Frees up any resources allocated during the use of an object
Example (only prototype shown):
~IntCell();
108
Copy Constructor
Special constructor that creates a new object, initialized to a copy of the same type of object Called in the following situations:
declaration with initalization
IntCell copy = original; IntCell copy(original);
if object is passed by value if object is returned by value
109
operator=
aka copy assignment operator Intended to copy the state of original into copy Called when = is applied to two objects AFTER both have previously been constructed
IntCell original; // constructor called IntCell copy; copy = original; // operator= called
110
Sample (advanced) code
class test { static int idcount; test.h const int id; int value; public: test(); test(int v); test(const test& x); ~test(); test& operator=(const test& other); friend ostream& operator<<(ostream& out, const test& f); }; 112
int test::idcount = 0;
test.cpp 1/2
test::test() : id (idcount++), value(0) { cout << "calling test(); object created is " << *this << "; address is " << this << endl; } test::test(int v) : id (idcount++), value(v) { cout << "calling test(" << v << "); object created is " << *this << "; address is " << this << endl; } test::test(const test& x) : id(x.id), value(x.value) { cout << "calling test(&test) on " << *this << "; address is " << this << endl; }
113
test.cpp 2/2
test::~test() { cout << "calling ~test() on " << *this << endl; } test& test::operator=(const test& other) { cout << "calling operator=(" << other << ")" << endl; test *tmp = new test(other); return *tmp; }
ostream& operator<<(ostream& out, const test& f) { out << "test[id=" << f.id << ",v=" << f.value << "]"; }
114
The one subroutine
test bar(test param) { return test(10); }
115
main() code and output, 1/6
test a(); cout << "attempted to create a: " << a << endl; cout << "--------------------------------------" << endl; test aa; cout << "created aa: " << aa << endl; attempted to create a: 1
-------------------------------------- calling test(); object created is test[id=0,v=0]; address is 0xff852a50 created aa: test[id=0,v=0]
116
main() code and output, 2/6
cout << "--------------------------------------" << endl; test b(1); cout << "created b: " << b << endl; -------------------------------------- calling test(1); object created is test[id=1,v=1]; address is 0xff852a48 created b: test[id=1,v=1]
117
main() code and output, 3/6
cout << "--------------------------------------" << endl; test *c = new test(2); cout << "created *c: " << *c << " at " << c << endl; test *d = new test; cout << "created *d: " << *d << " at " << d << endl;
-------------------------------------- calling test(2); object created is test[id=2,v=2]; address is 0xa009008 created *c: test[id=2,v=2] at 0xa009008 calling test(); object created is test[id=3,v=0]; address is 0xa009018 created *d: test[id=3,v=0] at 0xa009018
118
main() code and output, 4/6
cout << "--------------------------------------" << endl; cout << "about to invoke subroutine..." << endl; test e = bar(*c); cout << "finished invoking subroutine..." << endl;
-------------------------------------- about to invoke subroutine... calling test(&test) on test[id=2,v=2]; address is 0xff852a38 calling test(10); object created is test[id=4,v=10]; address is 0xff852a40 calling ~test() on test[id=2,v=2] finished invoking subroutine...
119
main() code and output, 5/6
cout << "--------------------------------------" << endl; test f = b; cout << "--------------------------------------" << endl; cout << "about to delete a test object..." << endl; delete c; // -------------------------------------- // calling test(&test) on test[id=1,v=1]; address is 0xff852a30 -------------------------------------- about to delete a test object... calling ~test() on test[id=2,v=2]
120
main() code and output, 6/6
cout << "--------------------------------------" << endl; cout << "assignment..." << endl; aa = b; cout << "--------------------------------------" << endl; cout << "about to leave main..." << endl; ---------------------------------------assignment... calling operator=(test[id=1,v=1]) calling test(&test) on test[id=1,v=1]; address is 0xa009008 ---------------------------------------about to leave main... calling ~test() on test[id=1,v=1] calling ~test() on test[id=4,v=10] calling ~test() on test[id=1,v=1] calling ~test() on test[id=0,v=0]
121