310 likes | 384 Views
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();
E N D
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++; else iter = 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 example • //THEDECLARATIONFILEOFTHECLASSPOINT(Point.h) • classPoint • { • public: • Point(); • Point(doublexval,doubleyval); • voidmove(doubledx,doubledy); • doublegetX()const; • doublegetY()const; • private: • double_x; • double_y; • };
C++ simple class example • //THEIMPLEMENTATIONFILEOFCLASSPOINT(Point.cpp) • #include"Point.h" • Point::Point():_x(0),_y(0){} • Point::Point(doublexval,doubleyval):_x(xval),_y(yval){} • voidPoint::move(doubledx,doubledy){ • _x=_x+dx; • _y=_y+dy; • } • doublePoint::getX()const{ • return_x; • } • doublePoint::getY()const{ • return_y; • }
C++ simple class example • Use example • #include<iostream> • #include“point.h” • intmain(){ • Pointp(0,0); • //Point p; • p.move(10,15); • constPointp2(20,12); • std::cout << p2.getx() << std::endl; • std::cout << p2.gety() << std::endl; • //p2.move(1,1);compilationerrorsincemoveisnotdeclaredconst • }
Member Initialization List class 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 Example: Circle::Circle(): _center(0,0) , _radius(1) {} • 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.
Inheritance Syntax: classDerived : publicBase{}; #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 • classPoint{.....} • intmain(){ • Point*p1=newPoint(0,0); • Pointp2(0,0); • p1->getX(); • (*p1).getX(); • p2.getX(); • (&p2)->getX(); • }
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: • A virtual destructor • A copy constructor • operator= (assignment)
Linked List Example Link data_ next_ List head_ data_ next_ data_ next_
Link • classLink{ • private: • Link*next_; • std::stringdata_; • public: • Link(conststd::string&data,Link*link); • Link(constLink&aLink);//copy constructor • virtual~Link();// destructor • voidsetNext(Link*link); • Link*getNext()const; • conststd::string&getData()const; • };
Link • Link::Link(conststd::string&data,Link*link):data_(data){ • setNext(link); • } • voidLink::setNext(Link*link){ • next_=link; • } • Link*Link::getNext()const{ • returnnext_; • } • conststd::string&Link::getData()const{ • returndata_; • } • Link::~Link(){}\\destructor • Link::Link(constLink&aLink){\\copy constructor • data_=aLink.getData(); • next_=0; • }
List • classList{ • private: • Link*head_; • Link*copy()const; • voidclear(); • public: • List(); • constLink*getHead()const; • voidinsertData(conststd::string&data); • voidremoveFirst(); • List(constList&aList); • virtual~List(); • List&operator=(constList&L); • };
List::List():head_(0){ } • constLink*List::getHead()const{ • returnhead_; • } • voidList::insertData(conststd::string&data){ • head_=newLink(data,head_); • } • voidList::removeFirst(){ • if(0!=head_){ • Link*tmp=head_; • head_=head_->getNext(); • deletetmp; • } • } • List::~List(){ • clear(); • } • voidList::clear(){ • while(0!=head_){ • removeFirst(); • } • }
Link*List::copy()const{ • if(0==getHead())return0; • else{ • Link*head=newLink(*getHead()); • Link*next=head; • for(Link*origPtr=getHead()->getNext();0!=origPtr; • origPtr=origPtr->getNext()){ • next->setNext(newLink(*origPtr)); • next=next->getNext(); • } • returnhead; • }} • List::List(constList&aList){ • head_=aList.copy(); • } • List&List::operator=(constList&L){ • if(this==&L) • return*this; • clear(); • head_=L.copy(); • return*this; • }
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.
Destructor • voidf(ListL){ • List*p=newList(); • while(...){ • ListL1; • ... • } • deletep; • } Is a destructor function of a reference parameter called at the end of the function? No!
/** • *Destructor:"deepdelete" • */ • List::~List(){ • clear(); • } • voidList::removeFirst() • { • if(0!=head_){ • Link*tmp=head_; • head_=head_->getNext(); • deletetmp; • } • } • voidList::clear(){ • while(0!=head_){ • removeFirst(); • } • }
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, • Pointq(2,2);Pointp(0,0); • p.moveTo(q);//moveTo(Point point) • Returned (by value) as a function result, • Declared with initialization from an existing object of the same class. • void f(Pointp){ • Pointtemp=p; • Pointtemp2(p); • …
Example • Listf(ListL); • intmain(){ • ListL1,L2; • ... • L2=f(L1);//copyconstructorcalledheretocopyL1 • } • Listf(ListL){ • Listtmp1=L;//copyconstructorcalledheretocopyL • Listtmp2(L);//copyconstructorcalledheretocopyL • ... • returntmp1;//copyconstructorcalledhere • }
Copy Constructor Declaration • classList{ • public: • …… • List(constList&L);//copyconstructor • ... • };
Copy Constructor Definition • List::List(constList&aList){ • head_=aList.copy(); • } • Link*List::copy()const{ • if(0==getHead())return0; • else{ • Link*head=newLink(*getHead()); • Link*next=head; • for(Link*origPtr=getHead()->getNext(); • 0!=origPtr;origPtr=origPtr->getNext()){ • next->setNext(newLink(*origPtr)); • next=next->getNext(); • } • returnhead; • } • }
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=(constList&L);
Operator= • 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
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 • List&List::operator=(constList&L){ • if(this==&L){ • return*this; • } • clear(); • head_=L.copy(); • return*this; • }