Download presentation
Presentation is loading. Please wait.
1
. Copying, casting, and more
2
Example: MyString u Lets put our knowledge of C++ classes to use u Define a class to represent a string u Replace all the calls to strdup, strcmp, … with methods that are clearer and handle memory allocation u [See MyString.h MyString.cpp]
3
Are we done yet? u Using MyString we can now write code For example MyString str1(“Foo”); MyString str2(“Bar”); … if( str1 > str2 ) str1 = str2; // Whoa! what does this do? …
4
Few Words on Copy… What does the assignment str1 = str2 do? High-level view: u “=“ is an operator (like “+”) u The commend specified here can be written (operator =)(str1,str2) The compiler searches for a function ( operator =) with arguments of type MyString Function name Arguments
5
operator = u For built-in types, the language behaves as though there are functions: int& operator=(int&, int); double& operator=(double&, double); … This is why we can write: int a, b; (a = b = 5)++; // equivalent to: b = 5; a = b; a++;
6
What about classes? u The same operator for a class X would have the type signature X& X::operator=(X const& ); Why X const& argument? To ensure that the right-hand side of copy does not change (why ref? later on) The X& return type? To allow for x = y = z like built-in types
7
MyString Revisited We never defined MyString::operator= u Why our example compiles? The compiler defines default instantiation of operator= This happens for every class for which the programmer did not define his own operator= Saves unneeded work for many classes
8
Default operator= u The default operator= copies all data members of the class u In our case, the result is MyString& MyString::operator=(MyString const& rhs) { m_length = rhs.m_length; m_string = rhs.m_string; return *this;// return reference to // current object }
9
Example Revisited void boringExample() { MyString str1(“Foo”); MyString str2(“Bar”); if( str1 > str2 ) str1 = str2; } Problem! u A memory location is deleted twice u Memory leak m_string str1: m_string str2: “Foo” “Bar” str1 constructor str2 constructor str1.operator=(str2) str1 destructor str2 destructor
10
The fix? u Define our own operator= MyString& MyString::operator=(MyString const& rhs) { delete [] m_string; m_length = rhs.m_length; init( rhs.m_string ); return *this; }
11
Is This Solution Water Tight? u What if a programmer writes MyString str(“foo”); … str = str; // senseless, but legal! What happens? u delete str.m_string u allocate a new str.m_string u copy this string onto itself…
12
Checking for Self-copy u Add another check at the beginning of the procedure MyString& MyString::operator=(MyString const& rhs) { if( this == &rhs ) return *this; …
13
Are We Out of The Woods? Consider the following code void doNothing( MyString S ) { } void anotherBoringExample() { MyString str(“foo”); doNothing(str); } What is wrong with this picture?
14
Copy Constructor What happens when we call DoNothing(str) ? A new MyString object is created on the stack u This object needs to be constructed It also needs to copy the value of str Copy constructor: MyString::MyString(MyString const& init);
15
Copy Constructor u This constructor is also called when initializing a new object MyString str2 = str1; is equivalent to writing MyString str2(str1); u In both cases the compiler calls copy constructor
16
Default Copy Construct u Same as with operator= u If not specified, default instantiation is by copying all data members Constructing each one with the value of the matching field in source In our example: MyString::MyString(MyString const& rhs) : m_length( rhs.m_length ), m_string( rhs.m_string ) {}
17
Example Revisited void doNothing( MyString S ) { } void anotherBoringExample() { MyString str(“foo”); doNothing(str); } Problem! str.m_string is deleted by the destructor
18
Fix? MyString::MyString(MyString const& rhs) { m_length = rhs.m_length; init( rhs.m_string ); }
19
Lessons If a class manages memory, then u Define you own operator= and copy constructor u Remember to copy all data members u Make sure to check for self-copy u Remember that operator= returns a reference to the object
20
Disallowing Copy u Some times we want to create classes in which object cannot be copied Large objects, such as a database “One time” data structure … u How do we ensure that object from this class are not copied?
21
Disallowing Copy Solution #1: u Do not define operator= and copy constructor Problem: u Compiler will define default versions u This is not what we want…
22
Disallowing Copy Solution #2: generate runtime error X& operator=(X const& x ) { assert(false); return *this; } Caveat: u Problems shows up very late in the development process…
23
Disallowing Copy Solution #3: u Define operator= as private class X { … private: X&operator=(X const&); }; u Cannot be called (compilation error) from outside methods of X
24
Copy & Inheritance class Base { … private: double m_x; int m_a; }; class Derived : public Base { … private: double m_z; }; Base a; Derived b; … a = b; default copy will m_x m_a a: m_x m_a m_z b:
25
Copy & Inheritance class A { public: virtual void f1(); virtual void f2(); int m_a; }; class B: public A { public: virtual void f1(); virtual void f3(); void f4(); int m_b; }; … A a; B b; a = b; class A { public: virtual void f1(); virtual void f2(); int m_a; }; class B: public A { public: virtual void f1(); virtual void f3(); void f4(); int m_b; }; … A a; B b; a = b; m_a m_b b: m_a a1: VTBLs f1 f2 f3 f1 f2 A B
26
Function Resolution u With overloading, we can have several functions with the same name u How does C++ know which function to call?
27
Example int square( int x ); double square( double x ); u In C, we get error: “conflicting types for ‘square’” u There can only be one function called square u In C++ these lines do not cause an error The two functions are considered different declarations
28
Function Resolution u How does C++ determine which function to call? u Lets check [resolution.cpp]
29
Function Resolution u In general, upon seeing the statement foo(x); The compiler searches for a function foo with argument types that match x or a function foo with argument types that can be casted to from the type of x
30
Function Resolution int square( int x ); double square( int x ); u This does not compile, why? u Based on return type alone, we cannot distinguish between the functions. u It is possible that we will encounter code like … square( 5 ); …
31
Function Resolution u How does C++ determine whether it can cast type A to type B ? Standard Casts: u int double, char int, etc. Tailored Casts: u casts introduced by the programmer
32
Example class MyClass { public: MyClass(int i); … }; u The constructor is viewed as a way of taking an integer an making it into a MyClass object
33
Example void foo( MyClass x ); … int i; … foo(i); // What happens here? The compiled code for the last line is eq. to { MyClass tmp(i); foo(tmp); }
34
Implicit Cast u This feature is useful for seamless operations u For example, MyString has a cast from char* u We can use “ ” in calling functions that expect MyString MyString str; … if( str == “foo” ) …
35
Implicit Cast class IntArray { public: IntArray(int size); // constructor bool operator==(IntArray const& rhs) const; int operator[](int i) const; … }; … IntArray A(5), B(5); … for( i = 0; i < 5; i++ ) if( A == B[i] ) // oops! should have been A[i] == B[i] … This creates a new temporary IntArray of size B[i] !!!
36
Explicit Keyword u A directive to compiler not to use constructor in implicit casts class IntArray { public: explicit IntArray(int size); // constructor … };
37
Lessons u C++ can create temporary objects “behinds the scenes” To avoid this: Use explicit keyword for constructors u Pass objects by reference void foo( MyClass const& Obj ); instead of void foo( MyClass Obj ); u Declare a private copy constructor
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.