Lecture 16
Pure Virtual Method
One where the virtual method of the base class is not implemented (only declared)
Perhaps because the class is so abstract that it is only meant to be subclassed, never itself instantiated
i.e. purpose is to organize subclasses, not create objects
Cannot declare a variable of this type or call its constructor.
class Student {
...
public:
// Method has no (*) impli
// Called a pure virtual method
virtual int fees() const = 0;
};
Student s; // would not work (cannot make student objects anymore)
Virtual Method UML Notation:
UML: Virtual and pure virtual methods -> indicated by italics Abstract classes: class name in italics Protected: # Static: Underline
Inheritance and Copy/Move
class Book {
public:
// Defines copy/move ctor
};
class Text: public Book {
string topic;
public:
// Does not define copy/move operations
};
Text t {"Algorithms", "LLRS", 500, "CS"};
Text t2=t; // No copy ctor in Text. What happens?
What happens?
Calls Book's copy constructor
and then goes field-by-field (i.e. default behaviour for the 'Text' part)
Same thing happens for other operations
To write your own operations for subclasses:
Text::Text (const Text &other):
Book {other}, topic {other.topic} {}
Text &Text::operator=(const Text &other) {
Book::operator=(other);
topic = other.topic;
return *this;
}
// This will compile but it is wrong (look at note)
Text::Text(Text &&other):
Book {other}, topic {other.topic} {}
// Look at this one instead
Text::Text(Text &&other): // **
Book {std::move(other)}, topic {std::move(other.topic)} {}
Text &Text::operator=(Text &&other) {
Book::operator=(std::move(other));
topic = std::move(other.topic);
return *this;
}
**Note:
other (so is other.topic) may be pointing at an rvalue, but it is a lvalue so long as the function is not returned yet - Thus, this is actually a COPY CONSTRUCTOR not MOVE CONSTRUCTOR
std::move(x) forces an lvalue x to be treated as an rvalue so that the "move" versions of the operations run
Operations given above are equivalent to the built-in - specialize as needed
Now consider:
Text t1{...}, t2{...};
Book *pb1 = &t1, *pb2 = &t2;
What if we do *pb1 = *pb2?
Partial assignment occurs: Copies only the book part How can we fix this? Try making operator=
virtual
class Book {
...
public:
virtual Book &operator=(const Book &other) {...}
};
class Text: public Book {
...
public:
virtual Text &operator=(const Book &other) override {...}
};
Note: For virtual methods, different return types from the parent class virtual methods are OK, but param types must be the same, or it's not an override (and won't compile); violates "is-a" (inheritance means is-a)
Now, assignment of a Book object to a Text object would be allowed
Text t{...};
Book b{...};
t=b; // uses a Book to assign a Text, this is bad (but it compiles)
Comic c{...};
t=c; // really bad (mixed assignment)
If operator=
is non-virtual - partial assignment through class pointers occurs, which is BAD If virtual - there is mixed assignment which is BAD
Recommendation: All superclasses should be abstract
Abstract Classes
Any class with a pure virtual method
Since abstract class needs at least one pure method, if you don't have one, use the destructor
Virtual destructor MUST be IMPLEMENTED
subclasses of abstract classes are also abstract unless they implement all pure method
Concrete: Class that is not abstract Example of Concrete Class:
class Regular: public Student { // refer to Student class above
public:
int fees() const override {
return 700*numCourses
}
}
Example of Abstract Class:
Rewrite Book hierarchy as Abstract:
UML:

Code:
class AbstractBook {
string title, author;
int length;
protected:
// prevents assignment through base class pointers from compiling, but implementation still available
AbstractBook &operator=(const AbstractBook &other);
public:
...
// Need at least 1 pure virtual method, so use destructors
virtual ~AbstractBook() = 0;
};
class NormalBook: public AbstractBook {
public:
...
NormalBook &operator=(const BormalBook &other) {
AbstractBook::operator=(other);
return *this;
}
~NormalBook() {} // other classes similar
}
Note: Virtual destructor MUST be implemented here as said before, even though it is pure virtual
AbstractBook::~AbstractBook() {}
Last updated
Was this helpful?