Presentation is loading. Please wait.

Presentation is loading. Please wait.

Issues with classes.

Similar presentations


Presentation on theme: "Issues with classes."— Presentation transcript:

1 Issues with classes

2 Outline In this lesson, we will:
Describe problems with the default behavior of copying or assigning of objects See that in addition to initialization, we may require clean-up Introduce the Copy constructor Assignment operator Destructor

3 Constructor and assignment
By default, A constructor can be used to initialize an object If you create a copy of an object, all member variables are copied Assignment copies all of the member variables When a local object goes out of scope, the memory is cleaned up When a dynamically allocated object is deleted, the memory is returned to the heap

4 Constructor and assignment
For example, all three local objects behave as expected: // Class declarations class Vector_3d; // Function declarations int main(); // Function definitions int main() { Vector_3d u{1, 2, 3}; Vector_3d v{u}; Vector_3d w{0, 0, 0}; w = u; std::cout << u.to_string() << std::endl; std::cout << v.to_string() << std::endl; std::cout << w.to_string() << std::endl; return 0; } Output: ( , , )

5 Constructor and assignment
The behavior is the same for dynamically allocated objects: // Function definitions int main() { Vector_3d *p_u = new Vector_3d{1, 2, 3}; Vector_3d *p_v = new Vector_3d{*p_u}; Vector_3d *p_w = new Vector_3d{0, 0, 0}; *p_w = *p_u; std::cout << p_u->to_string() << std::endl; std::cout << p_v->to_string() << std::endl; std::cout << p_w->to_string() << std::endl; delete p_u; delete p_v; delete p_w; return 0; } Output: ( , , )

6 The idea Consider the following problem: Now, we have problems:
Each object should have a unique ID that must stay unchanged Each object has a value that may change We want a count of the number of instances in existence Now, we have problems: When a copy is made: A new ID must be created The value should be copied over The instance count should be increased When an assignment is performed: Only the value should be copied over When an instance goes out of scope or is deleted The number of instances should be decreased

7 The idea Here is our class definition: class Container { public:
Container( double value ); std::string to_string() const; static int instance_count(); private: double value_; int id_; static int instance_count_; static int next_id_; }; int Container::instance_count_{0}; int Container::next_id_{ };

8 The idea Here are the definitions of the member functions:
Container::Container( double value ): value_{value}, id_{next_id_} { ++next_id_; ++instance_count_; } std::string Container::to_string() const { return std::to_string( id_ ) + ": " + std::to_string( value_ ); static int Container::instance_count() { return instance_count_;

9 Incorrect behavior If we execute this code the output is wrong:
int main() { Container a{32.5}; std::cout << a.to_string() << std::endl; { Container b{a}; std::cout << b.to_string() << std::endl; Container c{75.2}; std::cout << c.to_string() << std::endl; c = a; std::cout << "Instance count: " << Container::instance_count() << std::endl; } std::cout << "Instance count: " << Container::instance_count() << std::endl; return 0; Output: : : Instance count: 2

10 The copy constructor We must define a new constructor that is called when copying: class Container { public: Container( double value ); Container( Container const &original ); std::string to_string() const; static int instance_count(); private: double value_; int id_; static int instance_count_; static int next_id_; };

11 The copy constructor In this case, the copy constructor must:
Generate a new ID Increase the instance count Copy over the value from the original Container::Container( Container const &original ): value_{original.value_}, // Gets the value from 'original' id_{next_id_} { // Get a new ID ++next_id_; // Increases the ID ++instance_count_; // Increases the count }

12 The assignment operator
We must define a new assignment operator that is called when performing an assignment: class Container { public: Container( double value ); Container( Container const &original ); Container &operator=( Container const &rhs ); std::string to_string() const; static int instance_count(); private: double value_; int id_; static int instance_count_; static int next_id_; };

13 The assignment operator
In this case, the assignment operator must: Leave the ID and instant count unchanged Copy over the value from the right hand side Return a reference to the object (i.e., return *this) Container &Container::operator=( Container const &rhs ) { // Copy the value and leave the ID and count unchanged value_ = rhs.value_; return *this; }

14 The destructor Whenever a object goes out of scope or is deleted, we must call a destructor: class Container { public: Container( double value ); Container( Container const &original ); ~Container(); Container &operator=( Container const &rhs ); std::string to_string() const; static int instance_count(); private: double value_; int id_; static int instance_count_; static int next_id_; };

15 The destructor In this case, the destructor must:
Decrease the instance count Container::~Container() { --instance_count_; }

16 Correct behavior If we now execute the same code: Output:
int main() { Container a{32.5}; std::cout << a.to_string() << std::endl; { Container b{a}; std::cout << b.to_string() << std::endl; Container c{75.2}; std::cout << c.to_string() << std::endl; c = a; std::cout << "Instance count: " << Container::instance_count() << std::endl; } std::cout << "Instance count: " << Container::instance_count() << std::endl; return 0; Output: : : : : Instance count: 3 Instance count: 1

17 Behavior The copy constructor’s argument is always an instance of the class passed by constant reference: Class_name( Class_name const &original ); The assignment operator’s argument is always an instance of the class passed by constant reference and it returns *this: Class_name &operator=( Class_name const &rhs ); The destructor is always the class name with a ~ and it never takes any arguments: ~Class_name();

18 Looking ahead Next, we will look at two classes that require all of the functionality described here and where the default behavior would be wrong: An array class A linked list class

19 Summary Following this lesson, you now
Understand how classes can be used to hide member variables Know that one or constructors can be used to initialize member variables Like functions, they can have different arguments They are called either during variable declaration or during calls to the new operator Know that a destructor can be defined to clean up after an object is deallocated They are called either when a variable goes out of scope or during calls to the delete operator

20 References [1] No references?

21 Colophon These slides were prepared using the Georgia typeface. Mathematical equations use Times New Roman, and source code is presented using Consolas. The photographs of lilacs in bloom appearing on the title slide and accenting the top of each other slide were taken at the Royal Botanical Gardens on May 27, 2018 by Douglas Wilhelm Harder. Please see for more information.

22 Disclaimer These slides are provided for the ece 150 Fundamentals of Programming course taught at the University of Waterloo. The material in it reflects the authors’ best judgment in light of the information available to them at the time of preparation. Any reliance on these course slides by any party for any other purpose are the responsibility of such parties. The authors accept no responsibility for damages, if any, suffered by any party as a result of decisions made or actions based on these course slides for any other purpose than that for which it was intended.


Download ppt "Issues with classes."

Similar presentations


Ads by Google