C++ Crash Kurs
Dr. Dennis Pfisterer
Institut für Telematik, Universität zu Lübeck
http://www.itm.uni-luebeck.de/people/pfisterer
C++ classes
•
A
class
is user-defined type encapsulating
– data and
– operations on that data
•
Example
– Data of a Point might be int x, y; – Data of a Point might be int x, y; – Operations may be move, draw, …
•
Class operations are often called
– methods or
– member functions
•
A
class
offers the ability to be cleanly
– initialized (using constructors) and – destroyed (using destructors)
•
Class
– Defines the structure and behavior – Attributes of a class form the structure – Methods define the behavior
•
Object or Instance
Notation: Classes and Objects (Instances)
brighter(); darker();
Lamp
int brightness;
•
Object or Instance
– Called the “realization” of a class – Has an identity (this-pointer)
– Owns a separate set of attributes (state) – State changes through method invocation
•
Analogy
– Car vs. „My BMW“ – Human vs. „me“ l1; ln; … int brightness;• Declaration similar to struct‘s
– class Name
{
<access-control>
<data-member>
<method/function>
};
Declaring classes
repeat as often as necessary
<method/function>
};
• Access control for methods and attributes
– public: For anybody
– private: Only within this class
– protected: Within this class and within sub-classes
•
class
MyClassName
{
public
:
int method1();
void another_one();
private
:
Declaring classes
Ok. However, it is good practice to have only one private, protected and public block
private
:
void secret_one();
public
:
void another_public_one();
protected
:
void only_visible_to_inherited();
int my_protected_state;
}
;
public blockDon’t forget the ; as this will cause strange compiler
• Key word „class“ instead of „struct“ • Struct and Class are interchangeable
– struct’s now may also have methods – struct: „public“ is standard access level – class: „private“ is standard access level
C++ class vs. C struct
• Good practice: Always use class in C++
struct x { public: void f(); }; class x { public: void f(); };
1:1
struct x { void f(); //public }; class x { void f(); //private };≠
• A class can be used just like any other type
– Instances are defined just like predefined type instances
– Methods are invoked via variable_name.method_identifier
• Instances may be
Using classes
• Instances may be
– assigned,
– passed as arguments, and
– returned by functions
• Example (assignment)
– Point p1, p2;
p1.set( 1 , 3);
p2 = p1;
Automatic element-wise copy (just like with struct)
i.e.,
Using classes
//File: point.h class Point {
public:
set(int x, int y);
#include “point.h” #include <iostream> using namespace std;
int main(int argc, char** argv) set(int x, int y);
move(int dx, int dy); int x(); int y(); private: int x_; int y_; };
int main(int argc, char** argv) {
Point p;
p.set( 1, 3 );
cout << “p(“ << p.x() << ”, “ << p.y() << ”)” << endl; p.move( 10, 10 );
cout << “p(“ << p.x() << ”, “ << p.y() << ”)” << endl; }
Initializing classes
• How to ensure a „correct“ (i.e., predetermined) startup state
– Constructors
– Member initialization lists
• Constructors
– Member functions called just like the class itself – Have no return value
– Invoked whenever a class instance is allocated – Constructor overloading is allowed
• Member initialization lists
– Used instead of value assignments to members in constructors – Must be used to parameterize constructors of base classes
• Constructor invoked on
object instantiation
• Example
– Point p;
Constructors
//File: point.hclass Point {
public: Point()
{ x_=0; y_=0; } Point(int ax, int ay)
– Point p;
– Point p(1,2);
• Every class should have a
constructor
Point(int ax, int ay) { x_ = ax; y_ = ay; } set(int x, int y);
move(int dx, int dy); int x(); int y(); private: int x_; int y_; };
• Constructors can not be invoked like “normal” methods
– Point p;
p.Point(); Compiler error
• A constructor can be used to create new objects
Constructors
• A constructor can be used to create new objects
– Point p;
p.set(10, 10);
p = Point(100, 100);
– Point() constructs a temporary instance, which is then assigned to p – The temporary instance is popped automatically from the stack at the
• Used instead of value
assignments to members in
constructors
• Provides a more
object-Member initialization lists
…Point() { x_=0; y_=0; } Point(int ax, int ay)
{x_ = ax; y_ = ay; } …
• Provides a more
object-oriented style
– Data member are passed arguments to initialize themselves
– Should be used for (most) members
– Must be used to parameterize constructors of base classes
…
Point()
: x_(0), y_(0) {}
Point(int ax, int ay) : x_(ax), y_(ay) {}
Copy-constructor
• Used to assign one object to another
• Signature:
Classname
(const
Classname
& other);
– const is not mandatory, yet often sensible
• If no copy-constructor is implemented
– Default copy-constructor generated by the compiler – Creates 1:1 (shallow) copy of the other object
– Problem: Pointers are copied as well, not their pointed-at objects
Destructors
•
Counterpart to the constructors
– Invoked immediately before an object is removed from memory – Declaration just like a constructor with leading ~
– No overloading possible, no parameters, no return value
•
Perform possibly necessary cleanup
•
Perform possibly necessary cleanup
– Free reserved memory
– Close open files, network connections, etc.
•
Example
– class Lamp { public: ~Lamp(); };• Methods are functions in classes
– <modifier> <type> method-name(<parameter list>);
– Overloading of methods allowed
Implementing methods
• Instances have an identity
– Pre-defined „this“-pointer to itself
– Not available in static members
Implementing methods: Inline
class Lamp
{
public:
Lamp()
: on_(false), brightness_(10)
.h File
: on_(false), brightness_(10) {} void on() { on_ = true; } private: bool on_; int brightness_; };
Implementing methods: Separate .cpp File
class Lamp { public: Lamp(); #include “lamp.h“ //---Lamp:: Lamp().h File
.cpp File
Lamp(); void on(); private: bool on_; int brightness_; }; Lamp(): on_(false), brightness_(10) {}
//---void Lamp::on() { on_ = true; }
Implementing methods: const methods
• Constant methods
– May not modify attributes nor call non-const methods
– Only const-methods may be invoked on const instances
– <type> method-name(<parameter list>) const;
– <type> method-name(<parameter list>) const;
• Example
– class Lamp
{
public:
int brightness() const
{ return brightness; }
};
Implementing methods: static members
•
Static methods and attributes
– One instance per class, not per object – Can only access other static elements – Data elements must be explicitly defined – No this pointer available
•
class X
•
class X
{
public:
static void f(){};
static int i;
};
•
int X::i = 0;
void X::f() { … }
•
X::f();
• Access control is
class-not instance-specific
– Private & protected limit
access of others
– Instances of the same
• class A {
public:
void change(A& other) {
other.i = 10;
C++ class access control
– Instances of the same
class have access to
private members of any
other instance
other.i = 10; } private: int i; }; • A a, b; a.change(b);C++ class access control: friends
• Selectively disables access control of a class
– friend method-signature; or
friend class class-name;
• friends have full access to private/protected members
• friends have full access to private/protected members
• Example
#include “y.h“ class X { private: void f(); int x;friend void my_friend();
}; x.h void my_friend() { X x; x.f(); x.x = 19; y.cpp void my_friend(); y.h
Implicit type conversion using Constructors
• C++ performs implicit (safe) type conversions
– E.g., float x = 1; // Conversion from int to float
• C++ implicit type conversions extended to classes
– Implicit conversion using constructors or (global) functions
• Example • Example – class A { public: A () {} }; class B {
public: B(const A&){} };
void f(B b) {} int main() {
A a;
f(a); // Wants B, has A }
Preventing constructor conversion
• Automatic conversion sometimes not desired
– May introduce performance problems (many constructor calls) – Implicit conversion are not obvious to others reading the code
• Use explicit modifier to make implicit conversions explicit only
– Conversion must be made explicit by invoking the conversion constructor
• Example • Example – class A { public: A () {} }; class B {
public: explicit B(const A&) {} };
void f(B b) {} int main() {
A a;
• Demo
Operator Overloading
Operator Overloading
C++ class: Operator overloading
• Example
– class Vector {
public:
Vector(float x = 0.0, float y=0.0) : x_(x), y_(y) {} float x() const { return x_; }
float y() const { return y_; } private:
private:
float x; float y; };
Vector add(const Vector& a, const Vector& b) {
return Vector( a.x() + b.x(), a.y() + b.y() ); }
– Vector a, b, c; a = add( b, c);
• Assign new semantics to operators for custom data types
– Key word operator
– „Eye-candy“, same functionality can be achieved using method calls
• Variants
– Method of a class
– „Normal“ or „friend“ function
C++ class: Operator overloading
• Overloadable operators
new + % ~ > /= |= <<= >= -- () delete - ^ ! += %= << == && , [] new[] * & = -= ^= >> != || -> * delete[] / | < *= &= >>= <= ++ ->
Operator overloading: Using methods
•
Definition like normal methods of a class
– Only the identifier is special
– OperatorX: X is an operator, e.g. +
•
Example (binary operator+)
– class Vector {
{
…
Vector operator+(const Vector& other) {
return Vector( x_ + other.x_, y_ + other.y_); } };
•
Usage
– Vector x, a, b; – x = a + b; – x = a.operator+(b);Operator overloading: Using methods
• Example (unary operator-)
– class Vector
{
…
Vector
operator-
()
{
{
return Vector( -x_, -y_);
}
};
• Usage
– Vector a(1,1);
– a = -a;
(-1,-1)
– a = a.operator-();
• Definition like a normal Function
– Only the identifier is special (
operator
@, @ is an operator, e.g. +)
• Example (friend function for binary operator +)
– class Vector {
…
friend Vector operator+ (const Vector& a, const Vector& b); };
Operator overloading: Using (friend) functions
friend Vector operator+ (const Vector& a, const Vector& b); };
Vector operator+ (const Vector& a, const Vector& b) {
Vector res;
res.x = a.x + b.x; res.y = a.y + b.y; return res; }
• Usage
– Vector a, b, c; – a = b + c; – a = operator+ (b, c);Operator overloading: Using (friend) functions
• Example (friend function for unary operator -)
– class Vector
{
…
friend
Vector
operator-
(const Vector& v);
};
Vector
operator-
(const Vector& v)
{
return Vector(-v.x, -v.y);
}
• Usage
– Vector a, b; – b = -a;
Operator overloading: Demo
• Demo
Operator overloading: Parameters & return values/types
• Arguments and return values are arbitrary
– However, there is a useful pattern to follow
• Typical assumptions
– Arithmetic operations (like + and –, …) do not change their arguments – Arithmetic operations (like + and –, …) do not change their arguments
– Operator-assignments (like +=) and assignment (=) change the left-hand argument
– Logical operators do not change their arguments – Operations are chainable (e.g., a = b + d * e)
Operator overloading: Parameters & return values/types
• Arithmetic operations (like + and –, …) do not change their arguments • Logical operators (like <, >=, !=) do not modify the operands
• Rule
– Arguments that are not changed are passed as const references – Member functions are flagged const
– Member functions are flagged const
• Example (friend function)
– const A operator+(const A&left, const A& right); – bool operator>(const A&left, const A&right);
• Example (method)
– class A {
const A operator+(const A&right) const;
• Operator-assignments (like +=) and assignment (=) change
the left-hand argument
•
Rule
– Remove const from arguments that are about to be modified
Operator overloading: Parameters & return values/types
• Example (friend function)
– A& operator+=(A
&
left,
const
A
&
right);
• Example (method)
– class A
{
A& operator+=(
const
A
&
right)
;
Operator overloading: Parameters & return values/types
• Return value depends on the meaning of the operator
• If it produces a new value (e.g, +), return a const temporary object so that the result can not be used as an lvalue
– class A { int i;
const A operator+ (constA&other) {
{
return A( i += other.i ); }
}
• If it modifies the current value, return a (const) reference so that the operator can be chained
– class A { int i;
A& operator+=(constA&other) {
i += other.i; return *this; }
Operator overloading: Return optimization
•
Why NOT use “A tmp(1); return a;”?
– Using this prevents the compiler from performing “return optimization”
•
A tmp(1);
return tmp;
1. Temporary tmp object is created including constructor call 1. Temporary tmp object is created including constructor call 2. Copy-constructor copies tmp to return location on the stack 3. Destructor is called for tmp at the end of the scope
•
return A(1);
– Tells the compiler that this temporary is only intended a return value – Object is directly created on the stack
Optimized performance using constructor call instead of temporary
object
Operator overloading: Distinguish post- and prefix
•
Problem: Both ++x and x++ would be operator++
•
C++ workaround
– Use a dummy int parameter for the postfix operator
– No value or semantics, only provides a different method signature
•
Example
– class Vector { – class Vector {
…
public:
Vector operator++(); //Prefix Vector operator++(int); //Postfix };
•
Usage (prefix)
– ++x; – x.operator++();•
Usage (postfix)
– x++ – x.operator++(0);Operator overloading: Methods or (friend) functions?
•
If possible, prefer implementing as a method
– Always possible if the left operand is the class itself
– (Friend) functions mandatory when left operand is not the class itself
•
Example
– class A { private: private: int i; }; – A a;cout << “a=“ << a << endl;
– operator<<(cout, a); // Same as above: left operand is of type ostream – ostream& operator<<(ostream& os, const A& a)
{
os << a.i; return os;
• Recommendation
Operator overloading: Methods or (friend) functions?
Operator Recommended use
All unary operators Member
All unary operators Member
= () [] –> –>* Must be member
+= –= /= *= ^= &= |= %= >>= <<=
Member