From b44ae9644fd748290ca31800a732c7d5f68144e3 Mon Sep 17 00:00:00 2001
From: Sebastien Gilles <sebastien.gilles@inria.fr>
Date: Thu, 16 May 2019 18:07:10 +0200
Subject: [PATCH] Insist on the = 0 for pure virtual case, and underline it is
 nonetheless possible to provide an implementation for a pure virtual method.

---
 2-ObjectProgramming/6-inheritance.ipynb | 102 ++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/2-ObjectProgramming/6-inheritance.ipynb b/2-ObjectProgramming/6-inheritance.ipynb
index b900630..e7f160a 100644
--- a/2-ObjectProgramming/6-inheritance.ipynb
+++ b/2-ObjectProgramming/6-inheritance.ipynb
@@ -1320,6 +1320,108 @@
     "}"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Beware:** You **must** provide a definition for all non pure-virtual methods in your class. Not doing so leads to a somewhat cryptic error at link-time.\n",
+    "\n",
+    "You are not required to provide a definition for a pure virtual method, and you won't most of the time... But you might provide one if you want to do so, for instance to provide an optional default instantiation for the method in derived classes:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "struct VirtualBase\n",
+    "{\n",
+    "     virtual void Method() = 0;\n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "\n",
+    "void VirtualBase::Method()\n",
+    "{\n",
+    "    std::cout << \"Default implementation provided in abstract class.\" << std::endl;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "struct Concrete1 : public VirtualBase\n",
+    "{\n",
+    "    virtual void Method() override;\n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "struct Concrete2 : public VirtualBase\n",
+    "{\n",
+    "    virtual void Method() override;\n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "void Concrete1::Method()\n",
+    "{\n",
+    "    VirtualBase::Method(); // call to the method defined in the base class\n",
+    "    std::cout << \"This enables providing a base behaviour that might be completed if needed \"\n",
+    "        \"in derived classes, such as here by these lines you are reading!\" << std::endl;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "void Concrete2::Method()\n",
+    "{\n",
+    "    std::cout << \"Overriden implementation.\" << std::endl;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    std::cout << \"====== Concrete 1: uses up the definition provided in base class =====\" << std::endl;\n",
+    "    Concrete1 concrete1;\n",
+    "    concrete1.Method();\n",
+    "\n",
+    "    std::cout << \"\\n====== Concrete 2: doesn't use the definition provided in base class =====\" << std::endl;\n",
+    "    Concrete2 concrete2;\n",
+    "    concrete2.Method();\n",
+    "}"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
-- 
GitLab