CS247 Lecture 11
Last Time: Virtual, Override, destructors, vptr, vtables This Time: Pure virtual, polymorphic arrays, Polymorphic Big 5
Very Interesting!!:
If we do not provide an implementation for Shape::getArea()
, code won’t link “undefined reference to vtable error”.
We could make Shape::getArea()
return 0, or -1 to indicate “no area”, but it’s not natural. Really we want to avoid a definition for Shape::getArea()
entirely.
Solution: Declare Shape::getArea()
as a pure virtual function. A pure virtual function is allowed to not have an implementation. See pure virtual method.
Declares getArea()
as pure virtual by adding = 0
. Classes that declare a pure virtual function are called Abstract Class. Abstract classes cannot be instantiated as objects.
A class that overrides all of its parents pure virtual functions is called a concrete class. Concrete classes can be instantiated.
The purpose of abstract classes is to provide a framework to organize and define subclasses.
Polymorphic Arrays
What does f expect:
What it actually looks like:
All of Vec2{7,8}
is written into myArray[0]
. Half of Vec2{9,10}
is written into myArray[0]
. the other half is myArray[1]
.
Note
Lesson: Be very careful when using arrays of objects polymorphically. Use an array of pointers:
Vec3* myArray[2];
Other solution: vector ofVec3* s
Polymorphic Big 5
Let’s consider Book hierarchy again.
Compiler still provides us a copy constructor, that works as expected.
Let’s look at copy/move constructor and assignment operator to see their definition.
Copy Constructor:
Calls the copy constructor for the Book portion of Text. t
is a const Text&
, this is implicitly converted to a const Book&
.
Book does not have a default copy constructor. So we need it in the MIL.
Move Constructor:
t
and t.topic
are lvalues, so we’d invoke the copy constructor if we didn’t use std::move
. So we use move!
t is an rvalue reference so we know it is safe to steal title, author, length and topic via using std::move
to invoke move constructors. (Since rvalue will be gone, ok to modify them and return a random thing.)
Copy Assignment:
Book::operator=(t);
calls the Book assignment operator for the Book portion of this
Move Assignment:
All of these implementations are what the compiler gives by default.
Customize as necessary - for example, if doing manual memory management, you will need to write your own versions of these.
BUT: Are the compiler provided definitions actually that good?
Title, author and length are set, but topic remains unchanged
is defined as non-virtual. We’re calling operator=
method on a reference. We use the static type, call Book::operator=
, even though br1
and br2
are referencing texts. ????????????????
Some fields are copied, but not all. This is the partial assignment problem.
Our usual signature for Text is the following:
Can we just slap an override on the end of this? NO: signature don’t match in 2 places: return type, parameter type.
- Return type: this is actually okay: A subclass’s override method can return a subclass of the virtual function’s return type (if it’s a pointer or reference)
- Parameter type for overridden functions must match exactly
Signature must be the following:
Problem 1) can’t access other’s topic, because it’s a Book
, and Book
don’t have topics, only Texts
do.
Problem 2) other is a Book&
, so now this is legal:
We can set a Text to a Comic on RHS can be implicitly converted to a const Book&
.
This is the mixed assignment problem, which is where you can set subclass siblings to each other.
Non-virtual operator=
leads to partial assignment
virtual operator=
mixed assignment
To fix this, restructure the book hierarchy. Arrow to AbstractBook UML: Abstract classes and virtual methods are italicized (with stars).
Post Midterm!!
Next: CS247 Lecture 12