The C++ Language
Prof. Stephen A. Edwards
Copyright © 2001 Stephen A. Edwards All rights reserved
The C++ Language
Bjarne Stroupstrup, the language’s creator
C++ was designed to provide Simula’s
facilities for program organization together
with C’s efficiency and flexibility for systems
programming.
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ Features
Classes
• User-defined types
Operator overloading
• Attach different meaning to expressions such as a + b
References
• Pass-by-reference function arguments
Virtual Functions
• Dispatched depending on type at run time
Templates
• Macro-like polymorphism for containers (e.g., arrays)
Exceptions
Copyright © 2001 Stephen A. Edwards All rights reserved
Example: A stack in C
typedef struct { Creator function ensures stack
char s[SIZE]; is created properly.
int sp; Does not help for stack that is
} Stack; automatic variable.
Programmer could
inadvertently create
stack *create() { uninitialized stack.
Stack *s;
s = (Stack *)malloc(sizeof(Stack));
s->sp = 0;
return s;
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Example: A stack in C
char pop(Stack *s) {
if (sp = 0) error(“Underflow”);
return s->s[--sp];
}
void push(Stack *s, char v) {
if (sp == SIZE) error(“Overflow”);
s->s[sp++] = v; Not clear these are the only stack-
} related functions.
Another part of program can modify any
stack any way it wants to, destroying
invariants.
Temptation to inline these
computations, not use functions.
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ Solution: Class
Definition of both
class Stack {
representation and
char s[SIZE];
operations
int sp;
Public: visible outside the class
public:
Stack() { sp = 0; } Constructor: initializes
void push(char v) {
if (sp == SIZE) error(“overflow”);
s[sp++] = v;
}
char pop() {
if (sp == 0) error(“underflow”);
return s[--sp];
}
Member functions see
};
object fields like local
variables
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ Stack Class
Natural to use
Stack st;
st.push(‘a’); st.push(‘b’);
char d = st.pop();
Stack *stk = new Stack;
stk->push(‘a’); stk->push(‘b’);
char d = stk->pop();
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ Stack Class
Members (functions, data) can be public, protected,
or private
class Stack {
char s[SIZE];
public:
char pop();
};
Stack st;
st.s[0] = ‘a’; // Error: sp is private
st.pop(); // OK
Copyright © 2001 Stephen A. Edwards All rights reserved
Class Implementation
C++ compiler translates to C-style implementation
C++ Equivalent C implementation
class Stack { struct Stack {
char s[SIZE]; char s[SIZE];
int sp; int sp;
public: };
Stack()
void push(char); void st_Stack(Stack*);
char pop(); void st_push(Stack*, char);
}; char st_pop(Stack*);
Copyright © 2001 Stephen A. Edwards All rights reserved
Operator Overloading
For manipulating user-defined “numeric” types
Complex c1(1,5.3), c2(5);
Creating objects of the
Complex c3 = c1 + c2; user-defined type
c3 = c3 + 2.3;
Want + to mean
something different in
this context
Promote 2.3 to a
complex number here
Copyright © 2001 Stephen A. Edwards All rights reserved
Example: Complex number type
C++’s operator overloading makes it elegant
Class Complex {
double re, im;
public: Pass-by-reference
complex(double); reduces copying
complex(double, double);
complex& operator+=(const complex&);
};
Operator overloading
defines arithmetic
operators for the
complex type
Copyright © 2001 Stephen A. Edwards All rights reserved
References
Designed to avoid copying in overloaded operators
A mechanism for calling functions pass-by-reference
C only has pass-by-value
void swap(int x, int y) { /* Doesn’t work */
int tmp = x; x = y; y = tmp;
}
void swap(int &x, int &y) { /* Works with references */
int tmp = x; x = y; y = tmp;
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Complex Number Type
Member functions including operators can be defined
inside or outside the class definition
Complex&
Complex::operator+=(const complex &a)
{
re += a.re;
im += a.im;
return *this;
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Complex Number Class
Operators can also be defined outside classes
Complex operator+(const Complex a,
const Complex b) {
Complex sum = a; // Copy constructor
a += b; // invoke Complex::operator +=
return sum;
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Function Overloading
Overloaded operators a specific case of overloading
General: select specific method/operator based on
name, number, and type of arguments
void foo(int);
void foo(int, int); // OK
void foo(char *); // OK
int foo(char *); // BAD: return type not in signature
Copyright © 2001 Stephen A. Edwards All rights reserved
Const
Access control over variables, arguments.
Rock of
Provides safety Gibraltar
const double pi = 3.14159265; // Compile-time constant
int foo(const char* a) { // Constant argument
*a = ‘a’; // Illegal: a is const
}
class bar { // “object not modified”
int get_field() const { return field; }
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Templates
Our stack type is nice, but hard-wired for a single
type of object
Using array of “void *” or a union might help, but
breaks type safety
C++ solution: a template class
Macro-processor-like way of specializing a class to
specific types
Mostly intended for container classes
Standard Template Library has templates for
• strings, lists, vectors, hash tables, trees, etc.
Copyright © 2001 Stephen A. Edwards All rights reserved
Template Stack Class
template <class T> class Stack {
T s[SIZE];
int sp; T is a type argument
public:
Used like a type within
Stack() { sp = 0; } the body
void push(T v) {
if (sp == SIZE) error(“overflow”);
s[sp++] = v;
}
T pop() {
if (sp == 0) error(“underflow”);
return s[--sp];
}
};
Copyright © 2001 Stephen A. Edwards All rights reserved
Using a template
Stack<char> cs; // Instantiates the specialized code
cs.push(‘a’);
char c = cs.pop();
Stack<double *> dps;
double d;
dps.push(&d);
Copyright © 2001 Stephen A. Edwards All rights reserved
Display-list example
Say you want to draw a graphical scene
List of objects
• lines, arcs, circles, squares, etc.
How do you store them all in a single array?
void *list[10]; // Ugly: type-unsafe
How do you draw them all?
switch (object->type) { // Hard to add new object
case LINE: /* … */ break;
case ARC: /* … */ break;
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Inheritance
Inheritance lets you build derived classes from base
classes
class Shape { /* … */ };
class Line : public Shape { /* … */ }; // Also a Shape
class Arc : public Shape { /* … */ }; // Also a Shape
Shape *dlist[10];
Copyright © 2001 Stephen A. Edwards All rights reserved
Inheritance
class Shape {
double x, y; // Base coordinates of shape
public:
void translate(double dx, double dy) {
x += dx; y += dy;
}
Line inherits both the
}; representation and
member functions of
class Line : public Shape { the Shape class
};
Line l;
l.translate(1,3); // Invoke Shape::translate()
Copyright © 2001 Stephen A. Edwards All rights reserved
Implementing Inheritance
Add new fields to the end of the object
Fields in base class at same offset in derived class
C++ Equivalent C implementation
class Shape { struct Shape {
double x, y; double x, y
}; };
class Box : Shape { struct Box {
double h, w; double x, y;
}; double h, w;
};
Copyright © 2001 Stephen A. Edwards All rights reserved
Virtual Functions
class Shape { draw() is a virtual
virtual void draw(); function invoked
}; based on the actual
class Line : public Shape { type of the object, not
void draw(); the type of the pointer
};
class Arc : public Shape {
void draw(); New classes can be
}; added without having
to change “draw
Shape *dl[10]; everything” code
dl[0] = new Line;
dl[1] = new Arc;
dl[0]->draw(); // invoke Line::draw()
dl[1]->draw(); // invoke Arc::draw()
Copyright © 2001 Stephen A. Edwards All rights reserved
Implementing Virtual Functions
Involves some overhead Virtual table
Object of
for class Virt
type Virt
class Virt { &Virt::foo
vptr
int a, b; &Virt::bar
a
virtual void foo();
b
virtual void bar();
};
C++ Equivalent C implementation
void f(Virt *v) void f(Virt *v)
{ {
v->bar(); (*(v->vptr.bar))(v);
} }
Copyright © 2001 Stephen A. Edwards All rights reserved
Cfront
How the language was first compiled
Full compiler that produced C as output
C++ semantics therefore expressible in C
C++ model of computation ultimately the same
C++ syntax substantial extension of C
C++ semantics refer to the same model as C
So why use C++?
• Specifications are clearer, easier to write and maintain
Copyright © 2001 Stephen A. Edwards All rights reserved
Default arguments
Another way to simplify function calls
Especially useful for constructors
void foo(int a, int b = 3, int c = 4) { /* … */ }
C++ Expands to
foo(3) foo(3,3,4)
foo(4,5) foo(4,5,4)
foo(4,5,6) foo(4,5,6)
Copyright © 2001 Stephen A. Edwards All rights reserved
Declarations may appear anywhere
Convenient way to avoid uninitialized variables
void f(int i, const char *p)
{
if (i<=0) error();
const int len = strlen(p);
char c = 0;
for (int j = i ; j<len ; j++)
c += p[j];
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Multiple Inheritance
Rocket Science
Inherit from two or more classes:
class Window { … };
class Border { … };
class BWindow : public Window, public Border { … };
Copyright © 2001 Stephen A. Edwards All rights reserved
Multiple Inheritance Ambiguities
What happens with duplicate methods?
class Window { void draw(); };
class Border { void draw() };
class BWindow : public Window, public Border { };
BWindow bw;
bw.draw(); // Error: ambiguous
Copyright © 2001 Stephen A. Edwards All rights reserved
Multiple Inheritance Ambiguities
Ambiguity can be resolved explicitly
class Window { void draw(); };
class Border { void draw() };
class BWindow : public Window, public Border {
void draw() { Window::draw(); }
};
BWindow bw;
bw.draw(); // BWindow::draw() calls Window::draw()
Copyright © 2001 Stephen A. Edwards All rights reserved
Duplicate Base Classes
A class may be inherited more than once
class Drawable { … };
class Window : public Drawable { … };
class Border : public Drawable { … };
class BWindow : public Window, public Border { … };
BWindow gets two copies of the Drawable base class
Copyright © 2001 Stephen A. Edwards All rights reserved
Duplicate Base Classes
Virtual base classes are inherited at most once
class Drawable { … };
class Window : public virtual Drawable { … };
class Border : public virtual Drawable { … };
class BWindow : public Window, public Border { … };
BWindow gets one copy of the Drawable base class
Copyright © 2001 Stephen A. Edwards All rights reserved
Implementing Multiple Inheritance
A virtual function expects a pointer to its object
struct A { virtual void f(); }
struct B { virtual void f(); }
struct C : A, B { void f(); }
E.g., C::f() expects “this” to be a C*
But this could be called with “this” being a B*
In-memory
representation of a C
C *c or A *a A
B *b B
C
Copyright © 2001 Stephen A. Edwards All rights reserved
Implementation Using VT Offsets
struct A { int x; virtual void f(); }
struct B { int y; virtual void f(); virtual void g(); }
struct C : A, B { int z; void f(); } C’s vtbl
C c; c
&C::f 0
B *b = &c; vptr
x B in C’s vtbl
b->f(); // C::f()
b vptr &C::f –2
y &B::g 0
1. b is a B*: vptr has f(), g() z
2. Call C::f( this – 2 )
3. First argument now points to a C
Copyright © 2001 Stephen A. Edwards All rights reserved
Implementation Using Thunks
Create little “helper functions” that adjust this
Advantage: Only pay extra cost for virtual functions
with multiple inheritance
C’s vtbl
c
vptr &C::f
x B in C’s vtbl
b vptr &C::f_in_B
y &B::g
z
void C::f_in_B(void* this) {
return C::f(this – 2);
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Namespaces
Namespace pollution
• Occurs when building large systems from pieces
• Identical globally-visible names clash
• How many programs have a “print” function?
• Very difficult to fix
Classes suggest a solution
class A { void f(); };
class B { void f(); };
Two f’s are separate
Copyright © 2001 Stephen A. Edwards All rights reserved
Namespaces
Scope for enclosing otherwise global declarations
namespace Mine {
void print(int);
const float pi = 3.1415925635;
class Shape { };
}
void bar(float y) {
float x = y + Mine::pi;
Mine::print(5);
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Namespaces
using directive brings namespaces or objects into
scope
namespace Mine {
const float pi = 3.1415926535;
void print(int);
}
using Mine::print;
void foo() { print(5); } // invoke Mine::print
using namespace Mine;
float twopi = 2*pi; // Mine::pi
Copyright © 2001 Stephen A. Edwards All rights reserved
Namespaces
Namespaces are open: declarations can be added
namespace Mine {
void f(int);
}
namespace Mine {
void g(int); // Add Mine::g() to Mine
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Namespaces
Declarations and definitions can be separated
namespace Mine {
void f(int);
}
void Mine::f(int a) {
/* … */
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Exceptions
A high-level replacement for C’s setjmp/longjmp
struct Except {};
void bar() { throw Except; }
void foo() {
try {
bar();
catch (Except e) {
printf(“oops”);
}
}
Copyright © 2001 Stephen A. Edwards All rights reserved
Standard Template Library
I/O Facilities: iostream
Garbage-collected String class
Containers
• vector, list, queue, stack, map, set
Numerical
• complex, valarray
General algorithms
• search, sort
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ IO Facilities
C’s printing facility is clever but unsafe
char *s; int d; double g;
printf(“%s %d %g”, s, d, g);
Hard for compiler to typecheck argument types
against format string
C++ IO overloads the << and >> operators
cout << s << ‘ ‘ << d << ‘ ‘ << g;
Type safe
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ IO Facilities
Printing user-defined types
ostream &operator<<(ostream &o, MyType &m) {
o << “An Object of MyType”;
return o;
}
Input overloads the >> operator
int read_integer;
cin >> read_integer;
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ string class
Reference-counted for automatic garbage collection
string s1, s2;
s1 = “Hello”;
s2 = “There”;
s1 += “ goodbye”;
s1 = “”; // Frees memory occupied by “Hello goodbye”
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ STL Containers
Vector
• Dynamically growing, shrinking array of elements
vector<int> v;
v.push_back(3); // vector can behave as a stack
v.push_back(2);
int j = v[0]; // operator[] defined for vector
Copyright © 2001 Stephen A. Edwards All rights reserved
Iterators
Mechanism for stepping through containers
vector<int> v;
for ( vector<int>::iterator i = v.begin();
i != v.end() ; i++ ) {
int entry = *i;
}
…
v.begin() v.end()
Copyright © 2001 Stephen A. Edwards All rights reserved
Other Containers
Insert/Delete from
front mid. end random access
vector O(n) O(n) O(1) O(1)
list O(1) O(1) O(1) O(n)
deque O(1) O(n) O(1) O(n)
Copyright © 2001 Stephen A. Edwards All rights reserved
Associative Containers
Keys must be totally ordered
Implemented with trees
set
• Set of objects
set<int, less<int> > s;
s.insert(5);
set<int, less<int> >::iterator i = s.find(3);
map
•Associative Array
map<int, char*> m;
m[3] = “example”;
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ in Embedded Systems
Dangers of using C++
• No or bad compiler for your particular processor
• Increased code size
• Slower program execution
Much harder language to compile
• Unoptimized C++ code often much larger, slower than
equivalent C
Copyright © 2001 Stephen A. Edwards All rights reserved
C++ Features With No Impact
Classes
• Fancy way to describe functions and structs
• Equivalent to writing object-oriented C code
Single inheritance
• More compact way to write larger structures
Function name overloading
• Completely resolved at compile time
Namespaces
• Completely resolved at compile time
Copyright © 2001 Stephen A. Edwards All rights reserved
Inexpensive C++ Features
Default arguments
• Compiler adds code at call site to set default
arguments
• Long argument lists costly in C and C++ anyway
Constructors and destructors
• Function call overhead when an object comes into
scope (normal case)
• Extra code inserted when object comes into scope
(inlined case)
Copyright © 2001 Stephen A. Edwards All rights reserved
Medium-cost Features
Virtual functions
• Extra level of indirection for each virtual function call
• Each object contains an extra pointer
References
• Often implemented with pointers
• Extra level of indirection in accessing data
• Can disappear with inline functions
Inline functions
• Can greatly increase code size for large functions
• Usually speeds execution
Copyright © 2001 Stephen A. Edwards All rights reserved
High-cost Features
Multiple inheritance
• Makes objects much larger (multiple virtual pointers)
• Virtual tables larger, more complicated
• Calling virtual functions even slower
Templates
• Compiler generates separate code for each copy
• Can greatly increase code sizes
• No performance penalty
Copyright © 2001 Stephen A. Edwards All rights reserved
High-cost Features
Exceptions
• Typical implementation:
• When exception is thrown, look up stack until handler
is found and destroy automatic objects on the way
• Mere presence of exceptions does not slow program
• Often requires extra tables or code to direct clean-up
• Throwing and exception often very slow
Copyright © 2001 Stephen A. Edwards All rights reserved
High-cost Features
Much of the standard template library
• Uses templates: often generates lots of code
• Very dynamic data structures have high memory-
management overhead
• Easy to inadvertently copy large datastructures
Copyright © 2001 Stephen A. Edwards All rights reserved
Bottom-line
C still generates better code
Easy to generate larger C++ executables
Harder to generate slower C++ executables
Exceptions most worrisome feature
• Consumes space without you asking
• GCC compiler has a flag to enable/disable exception
support –fexceptions and –fno-exceptions
Copyright © 2001 Stephen A. Edwards All rights reserved