simplifying c++ for introductory programming

21
2004/02/25 Simplifying C++ for Introdu ctory Programming 1 Simplifying C++ for Introductory Programming Athens, 25 February 2004 by Pedro Guerreiro pg@ di . fct . unl .pt , http:// ctp . di . fct . unl . pt /~ pg Departamento de Informática Faculdade de Ciências e Tecnologia Universidade Nova de Lisboa 2829-516 Caparica, Portugal

Upload: dreama

Post on 08-Jan-2016

48 views

Category:

Documents


0 download

DESCRIPTION

Simplifying C++ for Introductory Programming. Athens, 2 5 February 2004. by Pedro Guerreiro [email protected] , http://ctp.di.fct.unl.pt/~pg Departamento de Informática Faculdade de Ciências e Tecnologia Universidade Nova de Lisboa 2829-516 Caparica, Portugal. Plan. Why? - PowerPoint PPT Presentation

TRANSCRIPT

Page 2: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

2

Plan Why?

Learning programming with C++ (!)

Simple classes.

Using the STL.

Library functions.

Introducing inheritance.

Visual programs.

Conclusion.

Page 3: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

3

Why do we want do simplify C++

C++ is a complex language.

C++ encompasses several programming paradigms.

C++ allows different styles of programming.

It is unrealistic to teach everything.

Suppose we have decided to use C++ to teach introductory programming.

Yes, we know that:

So being, is it reasonable to use C++ for introductory programming?

Yes, provided we simplify it.

Page 4: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

4

Ways of using C++C++, according to its author, Bjarne Stroustrup, can be used in four different ways, and combinations thereof:

As a better C.

For programming with abstract data types.

For object oriented programming.

For generic programming.

No, thanks.

OK, but not yet.

YES, but...

Yes, we will use this also.

And C++ was not meant to be used for teaching programming, as other languages were.

Page 5: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

5

Classes for abstract data types An abstract data type is a type or set of types, together with

the functions that are applicable to instances of the abstract

data type.

A class is an abstract data type together with an

implementation. (This is from Bertand Meyer’s book,

Object-Oriented Software Construction.)

In the first programs, we will program one class and that

class only has one object. (This is a very limited abstract

data type…)

That class simply encapsulates the “global variables” and

the functions that operate on those variables.

Page 6: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

6

Example: class Scoreclass Score {public: int maxPoints; double examWeight; double labWeight;

Score() { maxPoints = 15; examWeight = 0.70; labWeight = 0.30; }

int FinalScore(int exam, int lab) { return static_cast<int>(exam * examWeight + static_cast<double>(lab) / maxPoints * 20 * labWeight + 0.5); }

int FinalScoreWithBonus(int exam, int lab) { return Bonus(FinalScore(Bonus(exam), lab)); }

int Bonus(int x) { return x == 9 ? 10 : x; }};

class Score {public: int maxPoints; double examWeight; double labWeight;

Score() { maxPoints = 15; examWeight = 0.70; labWeight = 0.30; }

int FinalScore(int exam, int lab) { return static_cast<int>(exam * examWeight + static_cast<double>(lab) / maxPoints * 20 * labWeight + 0.5); }

int FinalScoreWithBonus(int exam, int lab) { return Bonus(FinalScore(Bonus(exam), lab)); }

int Bonus(int x) { return x == 9 ? 10 : x; }};

Observe: conditional operator instead of if-else statement.

This is for computing the final grade of a student in a course. There’s a maximum number of points he can get in the labs. The lab component has a certain weight in the final score and so does the exam. The final score is from 0 to 20, integer.

Observe: all functions are defined in the class declaration. There will be no .cpp file.

Page 7: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

7

Using the class#include <iostream>

#include "Score.h"

int main(){ Score s; int exam; int lab; int with_bonus; int final; for (;;) { std::cin >> exam >> lab >> with_bonus; if (!std::cin) break; if (with_bonus) final = s.FinalScoreWithBonus(exam, lab); else final = s.FinalScore(exam, lab); std::cout << "Score : " << final << std::endl; }}

#include <iostream>

#include "Score.h"

int main(){ Score s; int exam; int lab; int with_bonus; int final; for (;;) { std::cin >> exam >> lab >> with_bonus; if (!std::cin) break; if (with_bonus) final = s.FinalScoreWithBonus(exam, lab); else final = s.FinalScore(exam, lab); std::cout << "Score : " << final << std::endl; }}

Local variables. One of them, s, is of the class type.

Includes.

Function main.

Infinite loop...

... breaks at the end of file.

Functions are called for the target object.

Page 8: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

8

Simple classes

All data members and functions are public.

Default constructor only.

No destructor.

No static members.

No virtual functions.

No consts.

No default arguments.

No overloading.

Pass by value only.

Restricted set of rules for classes:

And also:• Each class is defined in a .h file.• The .h file has no #includes and

needs no control for repeated inclusion.

• The only .cpp file is the file where function main is programmed.

• All the #includes are done in the .cpp file.

Page 9: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

9

Using the STL

std::string s is better than char *s.

std::vector<int> v is better than int[1000] v.

std::sort readily available for sorting vectors.

Lists come for free with std::list<T>.

std::pair<T, U> useful for simple aggregation.

STL makes life much simpler:

And we can use all this without ever mentioning pointers!

Page 10: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

10

Simple example with the STLA class for a table of squares:

#include <iostream>#include <vector>

#include "Squares.h"

int main(){ Squares s; std::cout << "Up to? "; int n; std::cin >> n; s.Compute(n); for (int i = 0; i < static_cast<int>(s.squares.size()); i++) std::cout << " " << s.squares[i]; std::cout << std::endl;}

#include <iostream>#include <vector>

#include "Squares.h"

int main(){ Squares s; std::cout << "Up to? "; int n; std::cin >> n; s.Compute(n); for (int i = 0; i < static_cast<int>(s.squares.size()); i++) std::cout << " " << s.squares[i]; std::cout << std::endl;}

class Squares {public: std::vector<int> squares;

void Compute(int limit) { squares.clear(); for (int i = 0; i*i <= limit; i++) squares.push_back(i * i); }};

class Squares {public: std::vector<int> squares;

void Compute(int limit) { squares.clear(); for (int i = 0; i*i <= limit; i++) squares.push_back(i * i); }};

Page 11: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

11

Library functionsFirst programs need a lot of vector writing. We provide generic Write functions for writing generic vectors to an output stream, the items being separated parametrically:namespace mas {

template <class T>void Write(const std::vector<T>& v, const std::string& separator = " ", std::ostream& output = std::cout){ for (typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); i++) output << (i != v.begin() ? separator : "") << *i;}

template <class T>void WriteLine(const std::vector<T>& v, const std::string& separator = " ", std::ostream& output = std::cout){ Write(v, separator, output); output << std::endl;}

// ...

}

namespace mas {

template <class T>void Write(const std::vector<T>& v, const std::string& separator = " ", std::ostream& output = std::cout){ for (typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); i++) output << (i != v.begin() ? separator : "") << *i;}

template <class T>void WriteLine(const std::vector<T>& v, const std::string& separator = " ", std::ostream& output = std::cout){ Write(v, separator, output); output << std::endl;}

// ...

}

Yes, these functions use a lot of advanced techniques.

There are many other functions like these.

Page 12: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

12

Simple example with the STLOur main .cpp file for the squares example now becomes:

#include <iostream>#include <vector>

#include "Utilities.h"

#include "Squares.h"

int main(){ Squares s; std::cout << "Up to? "; int n; std::cin >> n; s.Compute(n); mas::WriteLine(s.squares);}

#include <iostream>#include <vector>

#include "Utilities.h"

#include "Squares.h"

int main(){ Squares s; std::cout << "Up to? "; int n; std::cin >> n; s.Compute(n); mas::WriteLine(s.squares);}

Using generic classes and generic functions is much easier than programming them.

Page 13: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

13

Introducing inheritanceWe introduce inheritance with numerical examples. First, a class that computes the solution of equation ex-2=0 using Newton’s method.

Do we need to program all this for each new equation?

class RealFunction {public: double Function(double x) { return ::exp(x) - 2.0; }

double Derivative(double x) { return ::exp(x); }

double Newton(double x0, double tolerance) { double x = x0; for (;;) { double delta = Function(x) / Derivative(x); if (::fabs(delta) < tolerance) break; x -= delta; } return x; }};

class RealFunction {public: double Function(double x) { return ::exp(x) - 2.0; }

double Derivative(double x) { return ::exp(x); }

double Newton(double x0, double tolerance) { double x = x0; for (;;) { double delta = Function(x) / Derivative(x); if (::fabs(delta) < tolerance) break; x -= delta; } return x; }};

Page 14: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

14

Abstract classes and virtual functionsWe replace the previous class by this abstract class with two pure virtual functions, one for Function, one for Derivative. This class cannot be used directly, but only through derivation.

class RealFunction {public: virtual double Function(double x) = 0;

virtual double Derivative(double x) = 0;

double Newton(double x0, double tolerance) { double x = x0; for (;;) { double delta = Function(x) / Derivative(x); if (::fabs(delta) < tolerance) break; x -= delta; } return x; }

// other functions programmed in terms of Function and Derivative

};

class RealFunction {public: virtual double Function(double x) = 0;

virtual double Derivative(double x) = 0;

double Newton(double x0, double tolerance) { double x = x0; for (;;) { double delta = Function(x) / Derivative(x); if (::fabs(delta) < tolerance) break; x -= delta; } return x; }

// other functions programmed in terms of Function and Derivative

};

Page 15: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

15

Derived classesNow we want to compute the zeros of tan(x) – x – 0.5. We define a class Tan1 that inherits from RealFunction and redefine the two virtual functions. Observe:

class Tan1: public RealFunction {public: double Function(double x) { return ::tan(x) - x - 0.5; }

double Derivative(double x) { return ::pow(1.0 / ::cos(x), 2) - 1; }};

class Tan1: public RealFunction {public: double Function(double x) { return ::tan(x) - x - 0.5; }

double Derivative(double x) { return ::pow(1.0 / ::cos(x), 2) - 1; }};

int main() { Tan1 r; std::cout << std::fixed << std::setprecision(15); x = r.Newton(0.85, 0.000001); std::cout << x << " " << r.Function(x) << std::endl;}

int main() { Tan1 r; std::cout << std::fixed << std::setprecision(15); x = r.Newton(0.85, 0.000001); std::cout << x << " " << r.Function(x) << std::endl;}

This is how we use it:This is more effective than introducing inheritance with examples such as “a cat is an animal” or “a student is a person”.

Page 16: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

16

Visual programs We want to teach students to write graphical programs that

use buttons, menus, etc.

With Microsoft Visual C++, it is not too difficult, even for novice programmers, to design dialog-based programs, provided they stick to a simple set of guidelines.

There is a major complication, however. Classes supplied Microsoft use CString, not std::string. We have to provide adapters that convert from one to the other. In the process, we simplify the usage, by keeping only the arguments that are needed at this stage.

A second complication arises for programs that draw: we do not want to have to deal with device contexts, allocating pens, COLORREFs, …

Page 17: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

17

Visual programs, exampleHere is an example of a OnBnClickedButton function, in a graphical variant of the Score problem:

void CScoreVisualDlg::OnBnClickedButton1()

{

Score s;

double x = mas::GetDouble(m_exam);

int y = mas::GetInt(m_lab);

int z = s.FinalScore(x, y);

mas::SetInt(m_final, z);

}

void CScoreVisualDlg::OnBnClickedButton1()

{

Score s;

double x = mas::GetDouble(m_exam);

int y = mas::GetInt(m_lab);

int z = s.FinalScore(x, y);

mas::SetInt(m_final, z);

}

These functions GetDouble, GetInt and SetInt come from our library.

Page 18: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

18

Visual utilitiesThe visual utilities are provided in a library. They involve advanced programming techniques, but are not difficult to use:

int AsInt(const CString& s, int base = 10){ int result; char *endp; errno = 0; result = ::strtol(s, &endp, base); if (s.IsEmpty() || errno || *endp) { errno = 0; std::string message("\"" + s + "\" is not a legal int value."); throw message; } return result;}

int GetInt(CWnd& x){ CString s; x.GetWindowText(s); return AsInt(s);}

int AsInt(const CString& s, int base = 10){ int result; char *endp; errno = 0; result = ::strtol(s, &endp, base); if (s.IsEmpty() || errno || *endp) { errno = 0; std::string message("\"" + s + "\" is not a legal int value."); throw message; } return result;}

int GetInt(CWnd& x){ CString s; x.GetWindowText(s); return AsInt(s);}

There are many functions like these.

Page 19: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

19

Class SimpleGraphics (1)For programs that draw, we use a class SimpleGraphics:class SimpleGraphics {protected: CPaintDC dc; COLORREF penColor; COLORREF penThickness; COLORREF brushColor;

public: COLORREF black; COLORREF blue; // ...

public: SimpleGraphics(CWnd* pWnd): dc(pWnd) { black = RGB(0, 0, 0); blue = RGB(0, 0, 255); // ... penColor = black; penThickness = 1; brushColor = white; }

//...

class SimpleGraphics {protected: CPaintDC dc; COLORREF penColor; COLORREF penThickness; COLORREF brushColor;

public: COLORREF black; COLORREF blue; // ...

public: SimpleGraphics(CWnd* pWnd): dc(pWnd) { black = RGB(0, 0, 0); blue = RGB(0, 0, 255); // ... penColor = black; penThickness = 1; brushColor = white; }

//...

//...

void SetPenColor(COLORREF color) { penColor = color; }

void SetPenThickness(int thickness) { penThickness = thickness; }

void SetBrushColor(COLORREF color) { brushColor = color; }

// ...

//...

void SetPenColor(COLORREF color) { penColor = color; }

void SetPenThickness(int thickness) { penThickness = thickness; }

void SetBrushColor(COLORREF color) { brushColor = color; }

// ...

Page 20: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

20

Class SimpleGraphics (2) void DrawLine(const CPoint& p1, const CPoint& p2) {...} void DrawPolyline(const std::vector<CPoint>& points) {...}

void DrawPolygon(const std::vector<CPoint>& points) { CPen pen(PS_SOLID, penThickness, penColor); CPen* pOldPen = dc.SelectObject(&pen); CBrush brush(brushColor); CBrush* pOldBrush = dc.SelectObject(&brush); CPoint *p = new CPoint[static_cast<int>(points.size())]; for (int i = 0; i < static_cast<int>(points.size()); i++) p[i] = points[i]; dc.Polygon(p, static_cast<int>(points.size())); delete [] p; dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); }

void DrawText(const std::string& s, const CPoint& p) { dc.TextOut(p.x, p.y, s.c_str()); }

};

void DrawLine(const CPoint& p1, const CPoint& p2) {...} void DrawPolyline(const std::vector<CPoint>& points) {...}

void DrawPolygon(const std::vector<CPoint>& points) { CPen pen(PS_SOLID, penThickness, penColor); CPen* pOldPen = dc.SelectObject(&pen); CBrush brush(brushColor); CBrush* pOldBrush = dc.SelectObject(&brush); CPoint *p = new CPoint[static_cast<int>(points.size())]; for (int i = 0; i < static_cast<int>(points.size()); i++) p[i] = points[i]; dc.Polygon(p, static_cast<int>(points.size())); delete [] p; dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); }

void DrawText(const std::string& s, const CPoint& p) { dc.TextOut(p.x, p.y, s.c_str()); }

};

Observe that polylines and polygons are represented externally by vectors of points (std::vector<CPoint>) and internally by arrays of points that are dynamically allocated.

Page 21: Simplifying C++ for Introductory Programming

2004/02/25 Simplifying C++ for Introductory Programming

21

Conclusion Yes, we can teach introductory programming with C++.

But we should use a simplified C++.

Simplification also means using the STL immediately.

Complications are avoided by utility functions and classes that must be provided.

With the help of the utility functions ,dialog-based programs with buttons, menus, etc., can be a part of introductory programming.

And so can programs that make simple drawings.

The rest of C++ comes afterwards, in a course of Object-Oriented Programming with C++.