Thread: Attempting to learn OO design with C++

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    3

    Attempting to learn OO design with C++

    Hello, I am attempting to make a Duck interface which can produce different types of ducks. I was hoping you could look over my code, and point out possible issues, or suggest alternatives to better design. Sorry, but I don't have any specific question. This is the 1st c++ program I've made in a while and I'm trying to figure smart pointers out.

    Here is my main Function

    Code:
    #include <iostream>#include "Duck.h"
    #include <memory>
    using std::cout;
    std::unique_ptr < Duck > createDuck();
    void operateDuck(Duck &);
    
    int main()
    {
      auto duck = createDuck();
      operateDuck(*duck);
      //duck = createDuck();
      //operateDuck(duck.get());
      return 0;
    }
    
    std::unique_ptr < Duck > createDuck()
    {
      int op;
      cout << "1 for mallard, 2 for model.." << endl;
      cin >> op;
      switch (op) {
      case 1:
        cout << "Creating Mallard..." << endl;
        return std::make_unique < MallardDuck > ();
        break;
      case 2:
        cout << "Creating Model..." << endl;
        return std::make_unique < ModelDuck > ();
        break;
      default:
        cout << "Continuing.." << endl;
      }
    }
    
    void operateDuck(Duck & duck)
    {
      int menuChoice;
      cout <<
          "Enter 1 to fly, 2 to flynomore, 3 to flyhigh, and 4 to quit, 5 to make new duck"
          << endl;
      cin >> menuChoice;
      while (menuChoice < 4) {
        cout << "Enter your choice again: " << endl;
        cin >> menuChoice;
        switch (menuChoice) {
        case 1:
          duck.performFly();
          break;
        case 2:
          duck.setFlyBehaviour(std::make_unique < FlyNoWay > ());
          break;
        case 3:
          duck.setFlyBehaviour(std::make_unique < FlyWithWings > ());
          break;
        case 4:
          cout << "Relinquishing command... " << endl;
          break;
        case 5:
          //recursively create new ducks until system failure
          break;
        default:
          cout << "No input..." << endl;
        }
      }
      cout << "Leaving OperateDuck() " << endl;
    
    }

    And here is my Duck.h

    Code:
    //// Created by playerone on 2019-10-24.
    //
    
    #ifndef OODESIGNEXAMPLES_DUCK_H
    #define OODESIGNEXAMPLES_DUCK_H
    #include "QuackBehaviour.h"
    #include "FlyBehaviour.h"
    #include <iostream>
    #include <memory>
    
    /*
     * class C {
     C(const C&) = default;               // Copy constructor
     C(C&&) = default;                    // Move constructor
     C& operator=(const C&) = default;  // Copy assignment operator
     C& operator=(C&&) = default;       // Move assignment operator
     virtual ~C() { }                     // Destructor
     };
     *
     */
    
    class Duck {
    public:
      Duck() = default;
      Duck(const Duck & other) = delete;  // we don't want to copy other duck's unique_ptr's
       Duck & operator=(const Duck &) = delete; //ducks are bred, not cloned
       Duck & operator=(Duck &&) = default;
       Duck(Duck && other) noexcept = default;
       virtual ~ Duck() = default;  //{std::cout << "Duck is being destroyed.." << endl;};
      virtual void display() = 0;
      void performFly() {
        flyBehaviour->fly();
      } void performQuack() {
        quackBehaviour->quack();
      }
      void swim() const {
        std::cout << "All ducks float, and are lighter than wood!" << endl;
      } void setFlyBehaviour(std::unique_ptr < FlyBehaviour > fb) {
        flyBehaviour = std::move(fb);
      }
      void setQuackBehaviour(std::unique_ptr < QuackBehaviour > qb) {
        quackBehaviour = std::move(qb);
      }
    private:
      std::unique_ptr < FlyBehaviour > flyBehaviour = nullptr;
      std::unique_ptr < QuackBehaviour > quackBehaviour = nullptr;
    };
    
    class MallardDuck:public Duck {
    public:
      MallardDuck() {
        //flyBehaviour = std::unique_ptr<FlyWithWings>(); //causes seg fault when flyBehaviour is protected (cant use assignment operator with unique_ptr??
        setFlyBehaviour(std::make_unique < FlyWithWings > ());
        setQuackBehaviour(std::make_unique < Quack > ());
      };
      //    ~MallardDuck() override { std::cout << "This mallard is being destroyed" << endl; }
      void display() override {
        std::cout << "Look at me I'm a mallard" << endl;
      }
    };
    
    class ModelDuck:public Duck {
    public:
      ModelDuck() {
        setFlyBehaviour(std::make_unique < FlyNoWay > ());
        setQuackBehaviour(std::make_unique < Squeak > ());
      };
      //    ~ModelDuck() override { std::cout << "This model is being destroyed" << endl; }
      void display() override {
        std::cout << "This model duck looks beautiful today!" << endl;
      }
    };
    
    #endif                          //OODESIGNEXAMPLES_DUCK_H
    The behaviour classes were trivial.
    There are some weird things I don't understand, like when I use
    Code:
    delete
    on the move constructor and assignment operator, the program still works? Other than that, I need to have good principles for an upcoming project in my software engineering course. This is what I was aiming for:

    https://i.imgur.com/tNp74ay.png
    Last edited by Salem; 10-31-2019 at 10:58 PM. Reason: removed crayola

  2. #2
    Registered User
    Join Date
    Apr 2019
    Posts
    3
    Here is FlyBehaviour class, QuackBehaviour is the same:

    Code:
    #ifndef OODESIGNEXAMPLES_FLYBEHAVIOUR_H
    #define OODESIGNEXAMPLES_FLYBEHAVIOUR_H
    
    #include <iostream>
    using namespace std;
    
    class FlyBehaviour {
    public:
      FlyBehaviour() = default;
      virtual ~ FlyBehaviour() {
        std::cout << "FlyBehaviour object is being destroyed.." << endl;
      };
      //FlyBehaviour(const FlyBehaviour&) = default;
      //FlyBehaviour&operator=(const FlyBehaviour&) = default;
      virtual void fly() = 0;
    };
    
    class FlyWithWings:public FlyBehaviour {
    public:
      void fly() override {
        cout << "I'm a flying duck" << endl;
    }};
    
    class FlyNoWay:public FlyBehaviour {
    public:
      void fly() override {
        cout << "I can't fly" << endl;
      };
    };
    
    #endif                          //OODESIGNEXAMPLES_FLYBEHAVIOUR_H
    Last edited by Salem; 10-31-2019 at 10:59 PM. Reason: Removed more crayola

  3. #3
    Registered User
    Join Date
    Apr 2019
    Posts
    3
    This DuckFactory is what I'm trying to implement.
    Code:
    //
    // Created by playerone on 2019-10-31.
    //
    
    #ifndef DUCKINTERFACE_DUCKFACTORY_H
    #define DUCKINTERFACE_DUCKFACTORY_H
    #include <iostream>
    #include <string>
    #include <map>
    #include <memory>
    #include "Duck.h"
    // Macro for class registration
    #define REGISTER_FACTORY(derivedClass) \
       namespace { auto registry_ ## derivedClass = ConcreteFactory<derivedClass>(#derivedClass);  }
    
    class DuckFactory {
    private:
      using FactoryMap = std::map < std::string, DuckFactory * >;
      static auto getRegister()->FactoryMap & {
        static FactoryMap classRegister {
        };
         return classRegister;
    } public:
        /** Register factory object of derived class **/
      static auto registerFactory(const std::string & name, DuckFactory * factory)->void {
        auto & reg = DuckFactory::getRegister();
        reg[name] = factory;
      } static auto showClasses()->void {
        std::cout << "Registered Classes:  " << endl;
        std::cout << "=====================" << endl;
        for (const auto & pair:DuckFactory::getRegister())
          std::cout << " + " << pair.first << endl;
      }
        /** Construct derived class returning raw ptr**/
          static auto makeRaw(const std::string & name)->Duck * {
        auto it = DuckFactory::getRegister().find(name);
        if (it != DuckFactory::getRegister().end())
          return it->second->construct();
        return nullptr;
      }
    
        /** Construct derived class returning unique ptr**/
      static auto makeUnique(const std::string & name)->std::unique_ptr < Duck > {
        return std::unique_ptr < Duck > (DuckFactory::makeRaw(name));
      }
    
      virtual ~ DuckFactory() = default;
      virtual auto construct() const->Duck * = 0;
    
    };
    
    template < typename DerivedClass > class ConcreteFactory:DuckFactory {
    public:
      //Register this global object on the factory register
      explicit ConcreteFactory(const std::string & name) {
        std::cerr << " [TRACE] " << "Registered Class = " << name << endl;
        DuckFactory::registerFactory(name, this);
      }
      auto construct() const->Duck * override {
        return new DerivedClass;
    }};
    
    #endif                          //DUCKINTERFACE_DUCKFACTORY_H
    and my main.cpp now looks like:
    Code:
    std::unique_ptr < Duck > createDuck();
    void operateDuck(Duck &);
    REGISTER_FACTORY(MallardDuck);
    REGISTER_FACTORY(ModelDuck);
    
    int main()
    {
      DuckFactory::showClasses();
      cout << endl;
      std::unique_ptr < Duck > objMallard1 = DuckFactory::makeUnique("MallardDuck");
      cout << " type of objMallard1 = " << objMallard1->getType() << endl;
    
      std::unique_ptr < Duck > objModel1 = DuckFactory::makeUnique("ModelDuck");
      cout << " type of obModel1 = " << objModel1->getType() << endl;
    
      operateDuck(*objModel1);
    
    }
    Is this an acceptable way of doing a factory design?
    Last edited by Salem; 10-31-2019 at 10:59 PM. Reason: Removed yet more crayola

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,537
    Well I would first suggest you learn either to "copy as text" in your IDE or "paste as text" in your browser before posting more code - thanks.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Where and how to learn about design patterns ?
    By MartinR in forum C++ Programming
    Replies: 5
    Last Post: 11-12-2015, 04:31 PM
  2. Replies: 0
    Last Post: 05-01-2015, 09:44 AM
  3. Replies: 0
    Last Post: 05-01-2015, 09:44 AM
  4. Attempting Linked Lists
    By mike_g in forum C Programming
    Replies: 14
    Last Post: 06-14-2007, 05:53 PM

Tags for this Thread