From af86ae575e88df8072922bceef094e8b890473fa Mon Sep 17 00:00:00 2001 From: Bjarne Stroustrup Date: Sat, 13 Feb 2016 18:06:11 -0500 Subject: [PATCH] some minor fixes in the class hierarchy section closing issue 524 --- CppCoreGuidelines.md | 50 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 1c60633..bdb083d 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -5661,16 +5661,40 @@ not using this (over)general interface in favor of a particular interface found ##### Reason -A class is more stable (less brittle) if it does not contain data. Interfaces should normally be composed entirely of public pure virtual functions and a default/empty virtual destructor. +A class is more stable (less brittle) if it does not contain data. +Interfaces should normally be composed entirely of public pure virtual functions and a default/empty virtual destructor. ##### Example class my_interface { public: // ...only pure virtual functions here ... - virtual my_interface() {} // or =default + virtual ~my_interface() {} // or =default }; + +##### Example, bad + class Goof { + public: + // ...only pure virtual functions here ... + // no virtual destructor + }; + + class Derived : public Goof { + string s; + // ... + }; + + void use() + { + unique_ptr p {new Derived{"here we go"}}; + f(p.get()); // use Derived through the Goof interface + g(p.get()); // use Derived through the Goof interface + } // leak + +The `Derived` is `delete`d through its `Goof` interface, so its `string` is leaked. +Give `Goof` a virtual destructor and all is well. + ##### Enforcement * Warn on any class that contains data members and also has an overridable (non-`final`) virtual function. @@ -5683,7 +5707,27 @@ Such as on an ABI (link) boundary. ##### Example - ??? + struct Device { + virtual void write(span outbuf) = 0; + virtual void read(span inbuf) = 0; + }; + + class D1 : public Device { + // ... data ... + + void write(span outbuf) override; + void read(span inbuf) override; + }; + + class D2 : public Device { + // ... differnt data ... + + void write(span outbuf) override; + void read(span inbuf) override; + }; + +A user can now use `D1`s and `D2`s interrchangeably through the interface provided by `Device`. +Furthermore, we can update `D1` and `D2` in a ways that are not binarily compatible with older versions as long as all access goes through `Device`. ##### Enforcement