system programming practical session 9 c++ classes

31
System Programming Practical Session 9 C++ classes

Post on 20-Dec-2015

216 views

Category:

Documents


0 download

TRANSCRIPT

System Programming

Practical Session 9

C++ classes

Outline

• STL examples

• Basic concepts

• Classes that hold pointers

• Destructor

• Copy constructor

• Operator=

void bad_clean_odd(std::vector<int> &vec){

for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter){

if (*iter % 2 != 0)vec.erase(iter); // @@BAD! After the call to erase, iter is invalid.

}}

void clean_odd(std::vector<int> &vec){

std::vector<int>::iterator iter = vec.begin();while (iter != vec.end()){

if (*iter % 2 == 0)iter++;

elseiter = vec.erase(iter);

}}int main(){

std::vector<int> vec; while(std::cin){ int i; //assume stdin holds only integers! std::cin >> i; vec.push_back(i); }

clean_odd(vec); for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter) std::cout << *iter << std::endl; return 0;}

int main(){std::map<std::string,int> stringCounts;std::string str;

while( std::cin >> str ){ std::map<std::string,int>::iterator found =

stringCounts.find(str);if (found != stringCounts.end())

found->second++;else

stringCounts.insert(std::make_pair(str, 1));}

std::map<std::string,int>::iterator iter; for( iter = stringCounts.begin(); iter != stringCounts.end(); ++iter) {

std::cout << "word: " << iter->first << ", count: " << iter->second << std::endl;

}

return 0;}

class Cow{private:  int _id;public:        Cow(int id): _id(id) {}        int getId() const {return _id;}}

// A comparator is a class that implements the operator()// It is passed as a parameter to the priority queue// and used to perform the comparisons among items in the queue.class CowComparator {        public:                bool operator()(const Cow &x, const Cow &y) {                        // return true if x < y, false otherwise                        return x.getId() < y.getId(); }}int main(){        typedef std::priority_queue<Cow, std::vector<Cow>, CowComparator> PrioQueue;        PrioQueue queue;        while(std::cin) {                int id;                // assume stdin holds only ints                std::cin >> id;                queue.push(Cow(id));        }        while(! queue.empty()){                std::cout << queue.top().getId() << std::endl;                queue.pop();

}}

template <typename T>bool from_string(T& t,                const std::string& s,                std::ios_base& (*f)(std::ios_base&) = std::dec){        std::istringstream iss(s);        return !(iss >> f >> t).fail();} template <typename T>std::string to_string(const T& t){        std::ostringstream o;        o << t;        return o.str();} //usage example:int main(){        std::vector<int> vec;        std::string line;        while(std::cin >> line){                int i;                if (! from_string(i, line)){                        std::cerr << "Please input only ints!!" << std::endl;                        continue;                }                vec.push_back(i);        }}

C++ simple class example1. // THE DECLARATION FILE OF THE CLASS POINT (Point.h)

 

2.   class Point 

3.   {

4.   public:

5.      Point();

6.      Point(double xval, double yval);

7.      void move(double dx, double dy);

8.      double getX() const;

9.      double getY() const;     

10.  private:

11.     double _x;

12.     double _y;

13.  };

C++ simple class example1. //  THE IMPLEMENTATION FILE OF CLASS POINT (Point.cpp) 

2. #include "Point.h"

3. Point::Point():_x(0), _y(0){ }

4. Point::Point(double xval, double yval):_x(xval),_y(yval){}

5. void Point::move(double dx, double dy) {

6.   _x = _x + dx;

7.   _y = _y + dy;

8. }

9. double Point::getX() const {

10.  return _x;

11.}

12.double Point::getY() const {  

13.  return _y;

14.}

C++ simple class exampleUse example1. #include <iostream>

2. #include “point.h”

3. int main( ){

4.     Point p(0,0);

5. //Point p;

6. p.move(10,15);

7. const Point p2(20,12);

8. std::cout << p2.getx() << std::endl; 

9. std::cout << p2.gety() << std::endl; 

10.     // p2.move(1,1);     compilation error since move is not declared const

11.}

Member Initialization Listclass Circle{

public:

Circle(); Circle(double centerX, double centerY, double radius); ………….. private:

Point _center;

double _radius;

};

Circle::Circle(): _center(0,0) , _radius(1) {}

Circle::Circle(double centerX, double centerY, double radius): _center(centerX, centerY) , _radius(radius) {}

Member Initialization List

Rules• The initial value can be any expression.

• The order the initialization happens is according to the order the member variables are declared.

• The member initialization list is executed before the body of the constructor.

•Not initializing a member via the initialization list means implicitly calling its default constructor

• Const members of a class can only be initialized via member initialization list.

Example: Circle::Circle(): _center(0,0) , _radius(1) {}

InheritanceSyntax: class Derived : public Base { };

#include “point.h”

#include “color.h” // suppose that we have defined class Color…

class Pixel : public Point{

Color _color;

……

};

Pixel::Pixel(Point point, Color color) : Point(point), _color(color) {}

// example of a derived constructor calling the base constructor

// Syntax: Derived::Derived(….) : Base(….) {…}

Operator>-

Shortcut for accessing members of an object pointed by a pointer.

ptr->member is a shortcut for (*ptr).member

1. class Point{.....}

2. int main( ){

3.     Point *p1=new Point(0,0);

4.     Point p2(0,0);

5.     p1->getX();

6.     (*p1).getX();

7.     p2.getX();

8.     (&p2)->getX();

9. }

Objects• In C++, object variables hold values, not object references.

• When one object is assigned to another, a copy of the actual values is made.

•When modifying an object in a function, you must remember to use call by reference.

•Two object variables cannot jointly access one object. If you need this effect in C++, then you need to use pointers.

•An object variable can only hold values of a particular type. If you want a variable to hold objects from different subclasses, you need to use pointers.

•If you want a variable point to either null or to an actual object, then you need to use pointers in C++.

Classes that hold pointers

A class that has a pointer data member should include the following member functions:

1. A virtual destructor

2. A copy constructor

3. operator= (assignment)

Linked List Example

Link data_ next_

List head_ data_ next_ data_ next_

Link1. class Link {

2.   private:

3.     Link* next_;

4.     std::string data_;

5.   public:

6.     Link(const std::string& data,  Link* link);

7.     Link(const Link& aLink); //copy constructor

8.     virtual ~Link(); // destructor

9.     void setNext(Link* link);

10.    Link* getNext() const;

11.    const std::string& getData() const;

12.};

1. Link::Link(const std::string& data,  Link* link) : data_(data) {

2.    setNext(link);

3. }

4. void Link::setNext(Link* link) {

5.    next_=link;

6. }

7. Link* Link::getNext() const {

8.    return next_;

9. }

10. const std::string& Link::getData() const {

11.    return data_;

12. }

13. Link::~Link() { } \\destructor

14. Link::Link(const Link& aLink) { \\copy constructor

15.    data_=aLink.getData();

16.    next_=0;

17. }

Link

List1. class List { 2.   private: 3.     Link* head_; 4.     Link* copy() const; 5.     void clear(); 6.   7.   public: 8.     List();  9.     const Link* getHead() const; 10.    void insertData(const std::string& data); 11.    void removeFirst(); 12.  13.    List(const List& aList); 14.    virtual ~List(); 15.    List& operator=(const List &L); 16.};

1. List::List() : head_(0) { } 2. const Link* List::getHead() const{ 3.    return head_; 4. } 5. void List::insertData(const std::string& data){ 6.    head_ = new Link(data, head_); 7. }8. void List::removeFirst(){ 9.    if (0 != head_) { 10.      Link* tmp = head_; 11.      head_ = head_->getNext(); 12.      delete tmp; 13.   } 14. } 15. List::~List() { 16.   clear(); 17. } 18. void List::clear(){ 19.    while (0 != head_) { 20.      removeFirst(); 21.   } 22. }

23. Link* List::copy() const { 24.   if (0 == getHead())     return 0; 25.   else { 26.       Link *head = new Link(*getHead()); 27.      Link *next = head; 28.      for (Link *origPtr = getHead()->getNext(); 0 !

= origPtr; 29. origPtr = origPtr->getNext()) { 30.         next->setNext(new Link(*origPtr)); 31.        next = next->getNext(); 32.      } 33.     return head; 34.   } } 35. List::List(const List &aList){ 36.     head_ = aList.copy(); 37. } 38. List & List::operator=(const List &L) { 39.   if (this == &L) 40.      return *this; 41.   clear(); 42.   head_ = L.copy(); 43.   return *this; 44. }

Destructor

An object's destructor function is called when that object is about to "go away“.

• For local variables (objects declared on the stack) and value parameters – When the variable goes out of scope.

• For dynamically allocated storage (objects on the heap) –

When the programmer frees the storage using delete.

Destructor1. void f(List L) {

2.           List *p = new List();

3.           while (...) {

4.             List L1;

5.             ...

6.           }

7.           delete p;

8.         }

Is a destructor function of a reference parameter called at the end of the function? No!

1. /**

2.   * Destructor: "deep delete"

3.   */

4.  List::~List() {

5.    clear();

6.  }

7. void List::removeFirst()

8. {

9.   if (0 != head_) {

10.    Link* tmp = head_;

11.    head_ = head_->getNext();    

12.    delete tmp;

13.  }

14.}

15. void List::clear(){

16.  while (0 != head_) {

17.    removeFirst();

18.  }

19.}

Copy Constructor An object's copy constructor is called (automatically, not by the

programmer) when it is created, and needs to be initialized to be a copy of an existing object.

This happens when an object is:

• Passed as a value parameter to a function,

1. Point q(2,2); Point p(0,0);

2. p.moveTo(q); //moveTo(Point point)

• Returned (by value) as a function result,

• Declared with initialization from an existing object of the same class.

1. void f(Point p){

2. Point temp=p;    

3. Point temp2(p); 

4. …

1. List f( List L );

2. int main() {

3.    List L1, L2;

4.    ...

5.    L2 = f( L1 );      // copy constructor called here to copy L1

6. }

7. List f( List L ) {

8.    List tmp1 = L;    // copy constructor called here to copy L

9.    List tmp2(L);     // copy constructor called here to copy L

10.   ...

11.   return tmp1;      // copy constructor called here 

12.}

Example

Copy Constructor Declaration

1. class List {

2.    public:

3. ……

4.     List(const List &L);// copy constructor

5.    ...

6. };

Copy Constructor Definition1. List::List(const List &aList){

2.     head_ = aList.copy();

3. }

4. Link* List::copy() const {

5.   if (0 == getHead())     return 0;

6.    else {

7.      Link *head = new Link(*getHead());

8.      Link *next = head;

9.      for (Link *origPtr = getHead()->getNext();

10.  0 != origPtr; origPtr = origPtr->getNext()) {

11.       next->setNext(new Link(*origPtr));

12.       next = next->getNext();

13.     }

14.    return head;

15.  }

16.}

Operator=

• By default, class assignment is just a field-by-field assignment

• If a class includes pointer fields, the default assignment operator causes aliasing which lead to trouble!

Solution: overload operator= to perform deep copy.

Syntax:

List & operator=(const List &L);

Note that operator= differs from the copy constructor in three important ways:

• The object being assigned to has already been initialized; therefore, if it has a pointer field, the storage pointed to must be freed to prevent a storage leak.

• It is possible for a programmer to assign from a variable into itself; for example: L1 = L1. The operator= code must check for this case, and do nothing.

• The operator= code must return a value

Operator=

Definition of operator= It should always include the following 4 sections:

• check assignment to self

• clear existing data members

• copy data member from other

• return this 1. List & List::operator=(const List &L) {

2.  if (this == &L) {

3.      return *this;

4.    }

5.    clear();

6.    head_ = L.copy();

7.    return *this;

8. }