Date post: | 11-Jan-2016 |
Category: |
Documents |
Upload: | liliana-grant |
View: | 233 times |
Download: | 1 times |
AdvancedAdvanced C++ C++ ProgrammingProgramming
Guillaume Caumon, September 2007Guillaume Caumon, September 2007
Introduction
C++ supports a variety of programming styles:
procedural (as FORTRAN, pascal, C, …)procedural (as FORTRAN, pascal, C, …)
object-oriented (as Eifel, JAVA, …)object-oriented (as Eifel, JAVA, …)
generic generic
Features interact with each other. Features interact with each other.
C++ is very flexible, C++ is very flexible, but also very confusing...but also very confusing...
Software development
Energy = CostEnergy = Cost
TimeTimeReleaseRelease
Maintenance:Maintenance:- Bug fixesBug fixes- User requestsUser requests- Backward compatibilityBackward compatibility
ConceptionConceptionDevelopmentDevelopmentTestingTesting
Introduction
The goal of this course is to provide some keys to The goal of this course is to provide some keys to choose the design which:choose the design which:
eases the maintenance process;eases the maintenance process;
optimizes performance;optimizes performance;
optimizes memory requirements.optimizes memory requirements.
Prerequisites
A working knowledge of C++ and of the basic A working knowledge of C++ and of the basic object-oriented concepts.object-oriented concepts.
What is a pointer ? What is a pointer ?
What is a class ? What is a class ?
What is inheritance ? What is inheritance ?
Outline
• Some Programming Rules
• Optimizing C++ programs
• Generic Programming
• A short STL overview
• Some Design Patterns
I- Some I- Some C++ features and C++ features and programming rulesprogramming rules
MiscellaneousMiscellaneous
Object designObject design
Resolving ambiguities: namespaceANSI featureANSI featurenamespace Gocad1 {namespace Gocad1 {
class MainWindow{ … };class MainWindow{ … };}}namespace Gocad2 { namespace Gocad2 { class MainWindow{ … };class MainWindow{ … };}}
using namespace Gocad1;using namespace Gocad1;
Gocad1::MainWindow window(…);Gocad1::MainWindow window(…);
using Gocad2::MainWindow;using Gocad2::MainWindow;
References or pointers ?
References are as cheap as pointers,References are as cheap as pointers, and more convenientand more convenient
Rules:Rules:• In function parameters, useIn function parameters, use
const T& varconst T& var instead ofinstead of T varT var• A nil reference does not exist, so use pointers A nil reference does not exist, so use pointers whenever you would need ‘nil references’.whenever you would need ‘nil references’.• pointers can be reassigned, references can’t.pointers can be reassigned, references can’t.
Goal: refer to objectsGoal: refer to objects
Exercise#include <vector>#include <vector>
class Traced {class Traced {public:public: Traced();Traced(); Traced( int parameter );Traced( int parameter ); Traced( const Traced& rhs );Traced( const Traced& rhs ); ~Traced();~Traced(); Traced& operator=( const Traced& rhs ); Traced& operator=( const Traced& rhs ); private:private: int impl_;int impl_;};};Using std::vector;Using std::vector;Class Dummy {Class Dummy { execute_val( vector<Traced> flags );execute_val( vector<Traced> flags ); execute_p( vector<Traced>* flags );execute_p( vector<Traced>* flags ); execute_ref( vector<Traced>& flags );execute_ref( vector<Traced>& flags ); execute_cref( const vector<Traced>& flags );execute_cref( const vector<Traced>& flags );};};
traced.h
Exerciseint main( int argc, char** argv ) {int main( int argc, char** argv ) { cout << "Creating the vector of data" << endl;cout << "Creating the vector of data" << endl; vector<Traced> data(2);vector<Traced> data(2); data[0] = Traced(0); data[1] = Traced(1);data[0] = Traced(0); data[1] = Traced(1); cout << "---------------------------\n" << cout << "---------------------------\n" << endl; endl; Dummy dummy;Dummy dummy; dummy.execute_val( data );dummy.execute_val( data ); dummy.execute_ptr( &data );dummy.execute_ptr( &data ); dummy.execute_ref( data );dummy.execute_ref( data ); dummy.execute_cref( data );dummy.execute_cref( data ); return 1;return 1;}}
./Traced./Tracedg++ -o Traced traced.cppg++ -o Traced traced.cpp
traced.cpp
Exceptions
Goals : improve program safetyGoals : improve program safety
try {try { // some code that might cause pbs// some code that might cause pbs}}
throw “message”throw “message”
catch ( “message” ) {catch ( “message” ) { // special processing “Doctor Watson”// special processing “Doctor Watson”}}
How ? Framework to bypass the function call stackHow ? Framework to bypass the function call stack
Constructor and assignment
int main() {int main() {String s1 = “tutu”;String s1 = “tutu”;String s2( “toto” );String s2( “toto” );s2 = s1;s2 = s1;
};};
class String {class String {public:public: String( const char* value );String( const char* value ); String( const String& rhs );String( const String& rhs ); ~String();~String(); String& operator=( const String& rhs);String& operator=( const String& rhs);private:private:
char* data_;char* data_;};};
file.h
Implicit type conversionsclass Rational {class Rational {
Rational( int num, int denom = 1 );Rational( int num, int denom = 1 );double operator double() const;double operator double() const;
};};void print_rational( void print_rational(
ostream& out, const Rational& fractionostream& out, const Rational& fraction) {) {
out << fraction->num() << “ / ” << out << fraction->num() << “ / ” << fraction->denom() << endl;fraction->denom() << endl;}}
int main( int argc, char** argv ) {int main( int argc, char** argv ) {Rational r(1,2);Rational r(1,2);double d = .5 * r;double d = .5 * r;print_rational( cout, d );print_rational( cout, d );return 1;return 1;
}}
Avoiding implicit conversions
class Rational {class Rational { explicit Rational( explicit Rational( int num, int num, int denom = 1 int denom = 1 );); operator double() const;operator double() const;};};
ANSI featureANSI feature
Overloading operators (I)
class Rational {class Rational {
Rational& operator =( const Rational& rhs );Rational& operator =( const Rational& rhs );
bool operator ==( const Rational& rhs );bool operator ==( const Rational& rhs );
Rational operator +( const Rational& rhs );Rational operator +( const Rational& rhs );
Rational& operator +=( const Rational& lhs );Rational& operator +=( const Rational& lhs );
Rational& operator++(); // ++a (prefix)Rational& operator++(); // ++a (prefix) Rational operator++(int); // a++ (postfix)Rational operator++(int); // a++ (postfix)};};
Overloading operators (II)
class Rational {class Rational { // …// … Rational operator+( int rhs );Rational operator+( int rhs );
friend Rational operator+( friend Rational operator+( int lhs, const Rational& rhs int lhs, const Rational& rhs
););};};
Rational operator+( Rational operator+( int lhs, const Rational& rhs int lhs, const Rational& rhs ) { //… }) { //… }
If the left-hand side of the expression is of a If the left-hand side of the expression is of a different type, the operator MUST be a non-member different type, the operator MUST be a non-member
Modifying non const member in const member
ANSI: use the ANSI: use the mutablemutable keyword keyword
Non ANSI: use const castNon ANSI: use const cast
Downgrade the const memberDowngrade the const member
I- I- C++ main programming C++ main programming rulesrules
MiscellaneousMiscellaneous
Object designObject design
What is OOP?
Object-Oriented Programming is a “philosophy” Object-Oriented Programming is a “philosophy” where the source code of a program is split into where the source code of a program is split into reusable objects. reusable objects.
What is an object, then?What is an object, then?
An object is made of two parts: An object is made of two parts:
- The interface The interface = catalog of the object features= catalog of the object features
-The implementation The implementation = internal machinery = internal machinery
The interface in C++
Usually defined in a header (.h) file:Usually defined in a header (.h) file:
class Car {class Car { public:public: // // Members Members can be accessed from any objectcan be accessed from any object
protectedprotected:: // // Can only be accessed by Car and its derived objectsCan only be accessed by Car and its derived objects
privateprivate:: // // Can only be accessed by Car for its own use.Can only be accessed by Car for its own use.};};
Aggregation or Composition?
Aggregation is a relationship in which one object is a part of another.
A aggregates B A aggregates B ==
B is part of A, but their B is part of A, but their lifetimes may be different lifetimes may be different
Ex: cEx: cars and wheels, engine, etc.
Composition is a relationship in which one object is an integral part of another
A composes B A composes B ==
B is part of A, and their B is part of A, and their lifetimes are the same lifetimes are the same
Ex: person and brain, lung, Ex: person and brain, lung, etc.etc.
CarCar WheelWheel PersonPerson BrainBrain44
Classes: Basic Design Rules
Minimize the number of public member functionsMinimize the number of public member functions
Avoid default constructorsAvoid default constructors
Hide implementation functions and dataHide implementation functions and data
Hide all member variablesHide all member variables
Avoid overloading (can be ambiguous)Avoid overloading (can be ambiguous)
Use Use constconst members whenever possible / needed members whenever possible / needed
Be aware of compiler generated functionsBe aware of compiler generated functions
Inheritance: quick review
““A circle A circle is ais a shape” shape”
CircleCircle
GeomShapeGeomShape
class GeomShape {class GeomShape { //… //… };};
class Circle : public GeomShape {class Circle : public GeomShape { //…//…};};
file.h
Public Inheritance Philosophy
Public inheritancePublic inheritance ‘is a’ ‘is a’
In other words:In other words:What is applies to a base class What is applies to a base class
applies to its derived classes applies to its derived classes
Three aspects to consider:Three aspects to consider:class public interfaceclass public interfaceclass relationship with derived classesclass relationship with derived classesclass internal cookwareclass internal cookware
Polymorphism
class Employee {class Employee {public :public : virtualvirtual float income();float income(); // 1000 // 1000 };};
class Boss : public Employee {class Boss : public Employee {public :public : virtual virtual float income();float income(); // 10000 // 10000};};
BossBoss
EmployeeEmployee
Mechanism that allows a derived class to modify the Mechanism that allows a derived class to modify the behavior of a member declared in a base classbehavior of a member declared in a base class
Polymorphism
BossBoss
EmployeeEmployee
A pure virtual function just defines the interface, and A pure virtual function just defines the interface, and leaves the implementation to derived classesleaves the implementation to derived classes
class Employee {class Employee {public :public : virtualvirtual float income() = 0;float income() = 0;
// not implemented// not implemented};};class Boss : public Employee {class Boss : public Employee {public :public : virtual virtual float income();float income(); // implemented // implemented};};
Public Inheritance PhilosophyInheritance of the interface
Inheritance of the implementation
Non virtual function
Mandatory Mandatory
Virtual function Mandatory By default,
Possible to redefine
Pure virtual function
Mandatory Re-definition is mandatory
Private Inheritance Philosophy
Private inheritancePrivate inheritance is implemented in term of is implemented in term ofThis is an equivalent variant of agregation:This is an equivalent variant of agregation:
class Car : private engine {class Car : private engine { //…//…};};
class Car {class Car {private: private: Engine engine_;Engine engine_;};};
Inheritance and fonctionsvirtual function
pure virtual function
Constructor
is…
Destructor is…
Isolated class
base class
pure abstract class
Derived (concrete) class
publicpublic
publicpublic
virtualvirtual
publicpublic
virtualvirtual
publicpublic
virtualvirtual
publicpublic
publicpublic
protectedprotected
publicpublic
NoNo
NoNo
Yes / noYes / no
Yes/noYes/no
YesYes
(must)(must)
YesYes
(must)(must)
YesYes
(must)(must)
NoNo
can can
have...have...
Polymorphism Mechanism
Derived::vf1Derived::vf1
Derived::vf3Derived::vf3
DerivedDerived
BaseBasevtbl_vtbl_
Base::vf1Base::vf1
Base::vf2Base::vf2
Base::vf3Base::vf3
BaseBasevtbl_vtbl_
Consequences
Never call a virtual function in a constructorNever call a virtual function in a constructor
Be aware of the increased size of classes Be aware of the increased size of classes with virtual functionswith virtual functions
Calling a virtual function is more expensive Calling a virtual function is more expensive than calling a non-virtual functionthan calling a non-virtual function
Never declare a virtual function inline Never declare a virtual function inline
Cast operators
Avoid c-style casting operators. Avoid c-style casting operators. ANSI C++ provides 4 cast operators :ANSI C++ provides 4 cast operators :
Type* reinterpret_cast<Type>(expression)Type* reinterpret_cast<Type>(expression)
Type* static_cast<Type>(expression)Type* static_cast<Type>(expression)
Type* const_cast<Type>(expression)Type* const_cast<Type>(expression)
Type* dynamic_cast<Type>(expression)Type* dynamic_cast<Type>(expression)
Additional guidelines...
Avoid multiple inheritance: use compositionAvoid multiple inheritance: use composition
Forbid default parameters in virtual functionsForbid default parameters in virtual functions
Don’t redefine (overload) a non virtual functionDon’t redefine (overload) a non virtual function
Differentiate between layering and inheritanceDifferentiate between layering and inheritance
II- II- Optimization in C++Optimization in C++
Optimization
Main issue: algorithm complexity and memory Main issue: algorithm complexity and memory requirementsrequirements
Main question: which part of the code should be Main question: which part of the code should be optimized ? optimized ?
20% of the code is used 80% of the time…20% of the code is used 80% of the time…
Code maintenance and debug vs. optimization.Code maintenance and debug vs. optimization.
Lazy evaluation
Compute only when neededCompute only when needed
Examples: Examples:
Matrix operator +Matrix operator +
Gocad association mechanismGocad association mechanism
Anticipated evaluation
Compute once, and cache information.Compute once, and cache information.
Examples: Examples:
Statistics managerStatistics manager
Dynamic arraysDynamic arrays
Return value optimization
class Complex {class Complex {////
};};const Complex operator*(const Complex operator*(
const Complex& a, const Complex b const Complex& a, const Complex b ) {) {
Complex c;Complex c;c.set_real( a.real() * b.real() );c.set_real( a.real() * b.real() );c.set_im( a.im() + b.im() );c.set_im( a.im() + b.im() );return c;return c;
}}
A first try...A first try...
Return value optimization
class Complex {class Complex {////
};};const Complex& operator*(const Complex& operator*(
const Complex& a, const Complex b const Complex& a, const Complex b ) {) {
Complex c;Complex c;c.set_real( a.real() * b.real() );c.set_real( a.real() * b.real() );c.set_im( a.im() + b.im() );c.set_im( a.im() + b.im() );return c;return c;
}}
A second try...A second try...
Return value optimization
class Complex {class Complex {////
};};const Complex operator*(const Complex operator*(
const Complex& a, const Complex b const Complex& a, const Complex b ) {) {
return Complex(return Complex( a.real() * b.real(), a.real() * b.real(),
a.im() + b.im() a.im() + b.im() ););
}}
A last try...A last try...
...But don’t alter your code quality for that !!...But don’t alter your code quality for that !!
Some rules...
Overload to avoid implicit type conversions (fine Overload to avoid implicit type conversions (fine tuning only)tuning only)
Prefer operator Prefer operator +=+= to operator to operator ++
Prefer generic programming to virtual functionsPrefer generic programming to virtual functions
Use inline functions, but not too much...Use inline functions, but not too much...
Postpone variable declarationPostpone variable declaration
Example: dynamic arraysGoal: add items dynamically to a set.Goal: add items dynamically to a set.
Problem:Problem:- dynamic memory allocation is time-consuming- dynamic memory allocation is time-consuming- the number of elements is not known from the start- the number of elements is not known from the start
Proposal:Proposal:
Allocate N elements, then add itemsAllocate N elements, then add items
Allocate 2N elements, then copy existing items, then add itemsAllocate 2N elements, then copy existing items, then add items
Allocate 4N elements, then copy existing items, then add itemsAllocate 4N elements, then copy existing items, then add items
III- III- Generic Programming in C++Generic Programming in C++
Parameterize classes…
Case of most container classes: store data Case of most container classes: store data of arbitrary types. of arbitrary types.
template<class T> class List {template<class T> class List {public :public : List( int nb_items );List( int nb_items ); ~List();~List();
void append_item( const T& item );void append_item( const T& item ); void remove_item( const T& item );void remove_item( const T& item ); void remove_all();void remove_all(); //…//…};};
list.h
… or fonctions/**/** * Swaps two objects of type T.* Swaps two objects of type T. * T should provide copy constructor* T should provide copy constructor * and operator=* and operator= */*/
template<class T> void swap(template<class T> void swap( T& t1, T& t2T& t1, T& t2););
swap.h
template<class T> void swap(template<class T> void swap( T& t1, T& t2T& t1, T& t2) {) { T tmp(t1);T tmp(t1); t1 = t2;t1 = t2; t2 = tmp;t2 = tmp;}}
swap.h
Templates
Template code is compiled only when it is Template code is compiled only when it is used (used (template instanciationtemplate instanciation))
Keyword ‘class’ (or ‘typename’) or ‘int’ can Keyword ‘class’ (or ‘typename’) or ‘int’ can be used to qualify template arguments.be used to qualify template arguments.
Members can be required from template Members can be required from template argumentsarguments
Example
template <class T> class List {template <class T> class List { //…//…};};
/**/** * Sorts a List of objects of type T.* Sorts a List of objects of type T. * T must provide order operators <* T must provide order operators < */*/
template <class T> class ListSorter {template <class T> class ListSorter {public :public : ListSorter( List<T>& list );ListSorter( List<T>& list ); void sort();void sort();private :private : List<T>& list_;List<T>& list_;};};
list.h
Functors
Goal: replace pointers to functionsGoal: replace pointers to functionsHow ?How ?[return type][return type] operator()(operator()( [type param] [type param] ););
Supports inline functions Supports inline functions Type checkingType checking
Example:Example: GeneratorGenerator Unary FunctionUnary Function Binary functionBinary function PredicatesPredicates … …
Generic Programming
Idea:Idea:
Replace virtual functions by mandatory Replace virtual functions by mandatory functions of template arguments…functions of template arguments…
Example: the Example: the GSTL [N. Rémy – A. Shtuka – B. Lévy – [N. Rémy – A. Shtuka – B. Lévy – J. Caers]J. Caers]
Example: Matrix objects (1)class Matrix {class Matrix {public:public: virtual double operator()( int i, int j ) = 0;virtual double operator()( int i, int j ) = 0;};};
class SymmetricMatrix : public Matrix {class SymmetricMatrix : public Matrix {Public:Public: virtual double operator()( int i, int j );virtual double operator()( int i, int j );};};
class UpperTriangularMatrix : public Matrix {class UpperTriangularMatrix : public Matrix {public:public: virtual double operator()( int i, int j );virtual double operator()( int i, int j );};};
Any problem?Any problem?
Static Polymorphism
• Replace virtual function by a template parameter
• Delegate the function to the template argument
Example: Matrix objects (2)class SymmetricStorage {class SymmetricStorage {public:public: double operator()( int i, int j );double operator()( int i, int j );};};class UpperTriangularMatrix {class UpperTriangularMatrix {//…//…};};
template <class STORAGE> class Matrix {template <class STORAGE> class Matrix {public:public: double operator()( int i, int j ) {double operator()( int i, int j ) { return storage_(i, j);return storage_(i, j); }}private:private: STORAGE storage_;STORAGE storage_;};};
Example: Matrix objects (2)
template <class STORAGE> class Matrix {template <class STORAGE> class Matrix {public:public: //…//… bool is_invertible();bool is_invertible(); bool is_sparse();bool is_sparse(); bool is_symmetric_positive_definite();bool is_symmetric_positive_definite();
//…//…};};
Delegation to Delegation to STORAGESTORAGE::- Burdens the Burdens the STORAGESTORAGE concept concept- May end up with inconsistencies May end up with inconsistencies
Example: Matrix objects (3)
template <class LEAF> class Matrix {template <class LEAF> class Matrix {public:public: LEAF& leaf() { LEAF& leaf() { return static_cast<LEAF&>( *this );return static_cast<LEAF&>( *this ); }}};};class SymmetricMatrix: class SymmetricMatrix: public Matrix<SymmetricMatrix> {public Matrix<SymmetricMatrix> { //…//…};};
Derived type is known at compile-timeDerived type is known at compile-timeDerived classes can define their own functionsDerived classes can define their own functions
Template Specialization
• Redefine the implementation for some template arguments
Application: metaprograms
template <int N> class Factorial {template <int N> class Factorial {public:public: enum { value = N * Factorial<N-1>::value };enum { value = N * Factorial<N-1>::value };};};
template <> class Factorial<1> {template <> class Factorial<1> {public:public: enum { value = 1 };enum { value = 1 };};};
Void f() {Void f() { const int fact4 = Factorial<4>::value;const int fact4 = Factorial<4>::value;}}
Application: metaprograms
Practical interest:Practical interest:
Specialization for optimizing behavior for small objectsSpecialization for optimizing behavior for small objects
Example :Example :Expand loops in vector / tensor /matrix calculusExpand loops in vector / tensor /matrix calculus
IV- IV- Overview of the STLOverview of the STL
Include files
#include <iostream>#include <iostream>
#include <vector>#include <vector>
#include <list>#include <list>
#include <utility>#include <utility>
#include <complex>#include <complex>
#include <map>#include <map>
……..
STL containers
std::vector<int> vect(30);std::vector<int> vect(30);
vect[2] = 3;vect[2] = 3;//…//…
for(for( std::vector<int>::iterator it(vect.begin());std::vector<int>::iterator it(vect.begin()); it != vect.end(); it++it != vect.end(); it++) {) { int& cur_value = *it;int& cur_value = *it;}}
V- Some design patternsV- Some design patterns
Finite state machine
Class TransactionBased {Class TransactionBased {public: public: start_task1();start_task1(); do_action1(…);do_action1(…); end_task1();end_task1();
start_task2(); start_task2(); // can be started only if task1 was completed// can be started only if task1 was completed do_action2(…);do_action2(…); end_task2();end_task2();
private:private: enum State{ UNDEF=0, TASK1=2, TASK2 = 4};enum State{ UNDEF=0, TASK1=2, TASK2 = 4};};};
To solve a linear system of equations…To solve a linear system of equations… add equation coefficients one by one, then invert the matrixadd equation coefficients one by one, then invert the matrix
Composite
GraphicGraphic
TextText PicturePictureLineLine
Treat a collection of objects as an object Treat a collection of objects as an object itselfitself
Singleton
Ensure that an object is instantiated only Ensure that an object is instantiated only onceonce
SingletonSingletonstatic Singleton* instance()static Singleton* instance()
Observer
Define a dependency between objectsDefine a dependency between objects
ConcreteObserverConcreteObserver
SubjectSubjectnotify()notify()
ObserverObserverupdate()update()
Factory method
Create the right type of elements in an Create the right type of elements in an abstract frameworkabstract framework
CreatorCreatorcreate_product()create_product() ProductProduct
ConcreteCreatorConcreteCreator ConcreteProductConcreteProduct
Conclusions
Concrete Applications...Concrete Applications...
Programming project Programming project Oral presentation of the use of one Oral presentation of the use of one particular design pattern in Gocad (Dec 2, particular design pattern in Gocad (Dec 2, 2005)2005)
In your master’s projectsIn your master’s projects
References
• Brokken et Kubat, C++ Annotations, http://www.icce.rug.nl/docs/cpp.shtml
• Stroustrup, Le langage C++ (3e ed.), Addisson Wesley, 1996.
• Gamma et al., Design Patterns, Addisson Wesley, 1995.
• Meyers, Effective C++, Addisson Wesley.• Meyers, More Effective C++, Addisson Wesley.• Meyers, Effective STL, Addisson Wesley.• http://www.oonumerics.org/blitz/papers/ • Gautier et al., Cours de Programmation par objets,
Masson.