listings-Chap19-README-onepage.md
Listings of Chap19.docx
This is the list of listings on one page. You can also view a linked summary.
Listing 19.1: Call-by-reference as a basis for polymorphism.
Book listing lst-0002-book.cpp:
// https://godbolt.org/z/71fE4zKhj
class Car { };
class VwBus : public Car { };
class ModelT : public Car { };
void letDrive(Car vehicle) { } // (ERR) Value parameter copies only base class
void letBrake(Car &vehicle) { } // Reference parameter
void letHonk(Car *vehicle) { } // Passed as pointer
int main() {
VwBus bus{ }; // automatic variable
Car *modelT = new ModelT{ }; // dynamically managed
letDrive(bus); // (ERR) gets copied to Car
letDrive(*modelT); // (ERR) gets copied to Car
letBrake(bus); // remains VwBus
letBrake(*modelT); // remains ModelT
letHonk(&bus); // remains VwBus
letHonk(modelT); // remains ModelT
}
Godbolt Listing lst-0002-godb.cpp, https://godbolt.org/z/71fE4zKhj:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/71fE4zKhj
class Car { };
class VwBus : public Car { };
class ModelT : public Car { };
void letDrive(Car vehicle) { } // (ERR) Value parameter copies only base class
void letBrake(Car &vehicle) { } // Reference parameter
void letHonk(Car *vehicle) { } // Passed as pointer
int main() {
VwBus bus{ }; // automatic variable
Car *modelT = new ModelT{ }; // dynamically managed
letDrive(bus); // (ERR) gets copied to Car
letDrive(*modelT); // (ERR) gets copied to Car
letBrake(bus); // remains VwBus
letBrake(*modelT); // remains ModelT
letHonk(&bus); // remains VwBus
letHonk(modelT); // remains ModelT
}
Listing 19.2: The Book class serves the reader and librarian actors.
Book listing lst-0003-book.cpp:
// https://godbolt.org/z/fdh4n5x84
struct Book {
auto getTitle() { return Title{"The C++ Handbook"s}; }
auto getAuthor() { return Author{"Torsten T. Will"s}; }
auto turnPage() { return /* Reference to the next page */ 42; }
auto getPage() { return "current page content"; }
auto getLocation() { return /* Shelf number/Book number */ 73; }
};
Godbolt Listing lst-0003-godb.cpp, https://godbolt.org/z/fdh4n5x84:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fdh4n5x84
struct Book {
auto getTitle() { return Title{"The C++ Handbook"s}; }
auto getAuthor() { return Author{"Torsten T. Will"s}; }
auto turnPage() { return /* Reference to the next page */ 42; }
auto getPage() { return "current page content"; }
auto getLocation() { return /* Shelf number/Book number */ 73; }
};
Listing 19.3: The changes of an actor usually only take place in one class.
Book listing lst-0004-book.cpp:
// https://godbolt.org/z/Tq9xbGxs4
struct Book {
auto getTitle() { return Title{"The C++ Handbook"s}; }
auto getAuthor() { return Author{"Torsten T. Will"s}; }
auto turnPage() { return /* Reference to the next page */ 42; }
auto getPage() { return "current page content"; }
auto getLocation() { return /* Shelf number/Book number */ 73; }
};
struct BookFinder {
Catalog catalog;
auto find(Book& book) { /* Shelf number/Book number */
catalog.findBookBy(book.getTitle(), book.getAuthor());
}
};
Godbolt Listing lst-0004-godb.cpp, https://godbolt.org/z/Tq9xbGxs4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tq9xbGxs4
struct Book {
auto getTitle() { return Title{"The C++ Handbook"s}; }
auto getAuthor() { return Author{"Torsten T. Will"s}; }
auto turnPage() { return /* Reference to the next page */ 42; }
auto getPage() { return "current page content"; }
auto getLocation() { return /* Shelf number/Book number */ 73; }
};
struct BookFinder {
Catalog catalog;
auto find(Book& book) { /* Shelf number/Book number */
catalog.findBookBy(book.getTitle(), book.getAuthor());
}
};
Listing 19.4: Does not follow the open/closed principle.
Book listing lst-0005-book.cpp:
// https://godbolt.org/z/vxTsveGjT
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
ShapeTag tag_;
double v1_, v2_;
Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
switch(shape->tag_) {
case ShapeTag::CIRC:
result += 3.1415 * shape->v1_ * shape->v1_;
break;
case ShapeTag::RECT:
result += shape->v1_*shape->v2_;
break;
}
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Shape>(10.)); // a circle
data.push_back(std::make_unique<Shape>(4., 6.)); // a rectangle
// calculate
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Godbolt Listing lst-0005-godb.cpp, https://godbolt.org/z/vxTsveGjT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vxTsveGjT
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
ShapeTag tag_;
double v1_, v2_;
Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
switch(shape->tag_) {
case ShapeTag::CIRC:
result += 3.1415 * shape->v1_ * shape->v1_;
break;
case ShapeTag::RECT:
result += shape->v1_*shape->v2_;
break;
}
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Shape>(10.)); // a circle
data.push_back(std::make_unique<Shape>(4., 6.)); // a rectangle
// calculate
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Listing 19.5: Follows the OCP.
Book listing lst-0006-book.cpp:
// https://godbolt.org/z/M6hsYa7or
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0; // abstract
};
class Rectangle : public Shape {
double w_, h_;
public:
Rectangle(double w, double h) : w_{w}, h_{h} {}
double area() const override { return w_ * h_; }
};
class Circle : public Shape {
double r_;
public:
Circle(double r) : r_{r} {}
double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
result += shape->area();
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Circle>(10.)); // a circle
data.push_back(std::make_unique<Rectangle>(4., 6.)); // a rectangle
// calculate
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/M6hsYa7or:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/M6hsYa7or
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0; // abstract
};
class Rectangle : public Shape {
double w_, h_;
public:
Rectangle(double w, double h) : w_{w}, h_{h} {}
double area() const override { return w_ * h_; }
};
class Circle : public Shape {
double r_;
public:
Circle(double r) : r_{r} {}
double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
result += shape->area();
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Circle>(10.)); // a circle
data.push_back(std::make_unique<Rectangle>(4., 6.)); // a rectangle
// calculate
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
GodboltId:rc67xWWfT
Book listing lst-0007-book.cpp:
// https://godbolt.org/z/rc67xWWfT
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
Point origin_; int width_; int height_;
public:
Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
virtual void setHeight(int height) { height_ = height; }
virtual int getHeight() const { return height_; }
virtual void setWidth(int width) { width_ = width; }
virtual int getWidth() const { return width_; }
virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
Square(Point o, int wh) : Rectangle{o, wh, wh} {}
void setHeight(int wh) override { width_ = height_ = wh; }
void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
rect.setWidth(5);
rect.setHeight(4);
auto areaValue = rect.getArea();
if(areaValue != 20) {
std::cout << "error!\n";
} else {
std::cout << "all fine\n";
}
}
int main() {
Rectangle rect{ {0,0}, 0,0 };
areaCheck( rect ); // Output: all fine
Square square{ {0,0}, 0 };
areaCheck( square ); // Output: error!
}
Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/rc67xWWfT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rc67xWWfT
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
Point origin_; int width_; int height_;
public:
Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
virtual void setHeight(int height) { height_ = height; }
virtual int getHeight() const { return height_; }
virtual void setWidth(int width) { width_ = width; }
virtual int getWidth() const { return width_; }
virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
Square(Point o, int wh) : Rectangle{o, wh, wh} {}
void setHeight(int wh) override { width_ = height_ = wh; }
void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
rect.setWidth(5);
rect.setHeight(4);
auto areaValue = rect.getArea();
if(areaValue != 20) {
std::cout << "error!\n";
} else {
std::cout << "all fine\n";
}
}
int main() {
Rectangle rect{ {0,0}, 0,0 };
areaCheck( rect ); // Output: all fine
Square square{ {0,0}, 0 };
areaCheck( square ); // Output: error!
}
Listing 19.6: Covariance for return types.
Book listing lst-0008-book.cpp:
// https://godbolt.org/z/Gxh4edc8n
using std::vector;
struct B {};
struct D : public B {};
struct Base1 {
virtual B& func();
};
struct Derived1 : public Base1 {
virtual D& func() override; // D& is covariant
};
struct Base2 {
virtual B& func();
};
struct Derived2 : public Base2 {
virtual D func() override; // (ERR) D is not covariant
};
struct Base3 {
virtual vector<B> func();
};
struct Derived3 : public Base3 {
virtual vector<D>& func() override; // (ERR) vector<D>& is not covariant
};
struct Base4 {
virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
virtual vector<D*>& func() override; // (ERR) different type, not covariant
};
Godbolt Listing lst-0008-godb.cpp, https://godbolt.org/z/Gxh4edc8n:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gxh4edc8n
using std::vector;
struct B {};
struct D : public B {};
struct Base1 {
virtual B& func();
};
struct Derived1 : public Base1 {
virtual D& func() override; // D& is covariant
};
struct Base2 {
virtual B& func();
};
struct Derived2 : public Base2 {
virtual D func() override; // (ERR) D is not covariant
};
struct Base3 {
virtual vector<B> func();
};
struct Derived3 : public Base3 {
virtual vector<D>& func() override; // (ERR) vector<D>& is not covariant
};
struct Base4 {
virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
virtual vector<D*>& func() override; // (ERR) different type, not covariant
};