{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Virtual methods for function overriding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "\n",
    "struct BaseClass {\n",
    "    virtual const char* final_message() const {\n",
    "        return \"We apologize for the incontinence.\";\n",
    "    }\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct DerivedClass : BaseClass {\n",
    "    const char* final_message() const override {\n",
    "        return \"This is the end.\";\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "BaseClass base;\n",
    "DerivedClass derived;\n",
    "BaseClass& ref = derived;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BaseClass: We apologize for the incontinence.\n",
      "DerivedClass: This is the end.\n",
      "BaseClass&: This is the end.\n"
     ]
    }
   ],
   "source": [
    "printf(\"BaseClass: %s\\n\", base.final_message());\n",
    "printf(\"DerivedClass: %s\\n\", derived.final_message());\n",
    "printf(\"BaseClass&: %s\\n\", ref.final_message());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Virtual methods for destructor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct BaseClass2 {\n",
    "    virtual ~BaseClass2() = default;\n",
    "};\n",
    "\n",
    "struct DerivedClass2 : BaseClass2 {\n",
    "    DerivedClass2() {\n",
    "        printf(\"DerivedClass() invoked.\\n\");\n",
    "    }\n",
    "    ~DerivedClass2() {\n",
    "        printf(\"~DerivedClass() invoked.\\n\");\n",
    "    }\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Constructing DerivedClass x.\n",
      "DerivedClass() invoked.\n",
      "Deleting x who point to a BaseClass2 instance.\n",
      "~DerivedClass() invoked.\n"
     ]
    }
   ],
   "source": [
    "printf(\"Constructing DerivedClass x.\\n\");\n",
    "BaseClass2* x { new DerivedClass2{} };\n",
    "printf(\"Deleting x who point to a BaseClass2 instance.\\n\");\n",
    "delete x;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Virtual methods for function overriding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "\n",
    "struct Logger {\n",
    "    virtual ~Logger() = default; // we use the default destroctor\n",
    "    virtual void log_transfer(long from, long to, double amount) = 0; // this == 0 means it's just an interface, no real implementations\n",
    "};\n",
    "\n",
    "struct ConsoleLogger : Logger {\n",
    "    void log_transfer(long from, long to, double amount) override {\n",
    "        printf(\"[cons] %ld -> %ld: %f\\n\", from, to, amount);\n",
    "    }\n",
    "};\n",
    "\n",
    "struct FileLogger : Logger {\n",
    "    void log_transfer(long from, long to, double amount) override {\n",
    "        printf(\"[file] %ld, %ld, %f\\n\", from, to, amount);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[cons] 1 -> 2: 3.000000\n",
      "[file] 1, 2, 3.000000\n"
     ]
    }
   ],
   "source": [
    "ConsoleLogger logger1;\n",
    "FileLogger logger2;\n",
    "logger1.log_transfer(1, 2, 3);\n",
    "logger2.log_transfer(1, 2, 3);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Virtual methods for general use"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Bank {\n",
    "    private:\n",
    "        Logger* logger;\n",
    "    public:\n",
    "        Bank(Logger* logger) : logger{ logger } {}\n",
    "        void set_logger(Logger* new_logger) {\n",
    "            logger = new_logger;\n",
    "        }\n",
    "        void make_transfer(long from, long to, double amount) {\n",
    "            if (logger) logger->log_transfer(from, to, amount);\n",
    "        }\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[cons] 3 -> 4: 5.000000\n",
      "[file] 3, 4, 5.000000\n"
     ]
    }
   ],
   "source": [
    "Bank bank{ new ConsoleLogger };\n",
    "bank.make_transfer(3, 4, 5);\n",
    "bank.set_logger( new FileLogger );\n",
    "bank.make_transfer(3, 4, 5);"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
