SVN / public / code / vorlesung-10 / ThingMain.cpp

Revision 8201
Date
Committerhb1003
Download
// Copyright 2026, University of Freiburg
// Chair of Algorithms and Data Structures
// Author: Hannah Bast <bast@cs.uni-freiburg.de>

#include <iostream>
#include <string>
#include <vector>

// A "thing" with a method `toString()` and not much else. Uses for explaining
// inheritance and polymorphism in C++.
class Thing {
public:
  // Returns a string representation of this thing.
  virtual std::string toString() const { return "THING"; }
  // Virtual destructor that does nothing so that the destructors of the
  // subclasses get called when they should.
  virtual ~Thing() {}
};

// An "integer thing" that inherits from `Thing` and holds an integer.
class IntegerThing : public Thing {
public:
  // Create an `IntegerThing` with the given value.
  IntegerThing(int value) { value_ = new int(value); }
  // IntegerThing(int value) : value_(value) {}
  // Destructor to free the allocated memory.
  ~IntegerThing() { delete value_; }
  // Returns a string representation of this integer thing.
  std::string toString() const override { return std::to_string(*value_); }

private:
  // The int value.
  int *value_;
  // int value_;
};

// A "string thing" that inherits from `Thing` and holds a string.
class StringThing : public Thing {
public:
  // Create a `StringThing` with the given value.
  StringThing(const char *s) { content_ = s; }
  // Returns a string representation of this string thing.
  std::string toString() const override { return content_; }

private:
  // The string value.
  std::string content_;
};

// Main program for various demos.
int main() {
  std::cout << std::endl;

  // Create a number of things and print them.
  {
    Thing thing1;
    IntegerThing thing2(42);
    StringThing thing3("doof");
    std::cout << thing1.toString() << std::endl;
    std::cout << thing2.toString() << std::endl;
    std::cout << thing3.toString() << std::endl;
    std::cout << std::endl;
  }

  // Show the sizes of each of the three classes.
  {
    std::cout << "sizeof(Thing)        : " << sizeof(Thing) << std::endl;
    std::cout << "sizeof(IntegerThing) : " << sizeof(IntegerThing) << std::endl;
    std::cout << "sizeof(StringThing)  : " << sizeof(StringThing) << std::endl;
    std::cout << std::endl;
  }

  // Create a vector of things and print them.
  {
    std::vector<Thing> things;
    Thing thing1;
    IntegerThing thing2(42);
    StringThing thing3("doof");
    things.push_back(thing1);
    things.push_back(thing2);
    things.push_back(thing3);
    for (const Thing &thing : things) {
      std::cout << thing.toString() << std::endl;
    }
    std::cout << std::endl;
  }

  // The same thing, now with pointers to things.
  {
    std::vector<Thing *> things;
    Thing thing1;
    IntegerThing thing2(42);
    StringThing thing3("doof");
    things.push_back(&thing1);
    things.push_back(&thing2);
    things.push_back(&thing3);
    for (const Thing *thing : things) {
      std::cout << thing->toString() << std::endl;
    }
    std::cout << std::endl;
  }

  // Show what can happen with inheritance and destructors.
  {
    // IntegerThing thing(42);
    Thing *thing;
    thing = new IntegerThing(42);
    delete thing;
  }

  // Show RTTI stuff (runtime type information).
  {
    Thing *thing = new IntegerThing(42);
    IntegerThing *integerThing = dynamic_cast<IntegerThing *>(thing);
    StringThing *stringThing = dynamic_cast<StringThing *>(thing);
    // IntegerThing *integerThing = static_cast<IntegerThing *>(thing);
    // StringThing *stringThing = static_cast<StringThing *>(thing);
    std::cout << "Adress of thing        : " << thing << std::endl;
    std::cout << "Adress of integerThing : " << integerThing << std::endl;
    std::cout << "Adress of stringThing  : " << stringThing << std::endl;
    std::cout << std::endl;
    delete thing;
  }

  return 0;
}