第2章:課題の実装

はじめに

本章では、CPP Module 05の各演習を実装します。

---

1. ex00: Mommy, when I grow up, I want to be a bureaucrat!

1.1 課題の要件

  • Bureaucratクラス(name, grade)
  • gradeは1(最高)から150(最低)
  • 範囲外でGradeTooHighException/GradeTooLowException
  • incrementGrade/decrementGradeメソッド
  • <<演算子オーバーロード
  • 1.2 Bureaucratクラス

    // Bureaucrat.hpp
    #ifndef BUREAUCRAT_HPP
    #define BUREAUCRAT_HPP
    
    #include <string>
    #include <iostream>
    #include <exception>
    
    class Bureaucrat {
    public:
        class GradeTooHighException : public std::exception {
        public:
            const char* what() const throw();
        };
    
        class GradeTooLowException : public std::exception {
        public:
            const char* what() const throw();
        };
    
    private:
        const std::string _name;
        int _grade;
    
        static const int HIGHEST_GRADE = 1;
        static const int LOWEST_GRADE = 150;
    
    public:
        Bureaucrat();
        Bureaucrat(const std::string& name, int grade);
        Bureaucrat(const Bureaucrat& other);
        Bureaucrat& operator=(const Bureaucrat& other);
        ~Bureaucrat();
    
        const std::string& getName() const;
        int getGrade() const;
    
        void incrementGrade();
        void decrementGrade();
    };
    
    std::ostream& operator<<(std::ostream& os, const Bureaucrat& bureaucrat);
    
    #endif
    
    // Bureaucrat.cpp
    #include "Bureaucrat.hpp"
    
    // 例外クラスの実装
    const char* Bureaucrat::GradeTooHighException::what() const throw() {
        return "Grade is too high";
    }
    
    const char* Bureaucrat::GradeTooLowException::what() const throw() {
        return "Grade is too low";
    }
    
    // コンストラクタ
    Bureaucrat::Bureaucrat() : _name("Unknown"), _grade(LOWEST_GRADE) {}
    
    Bureaucrat::Bureaucrat(const std::string& name, int grade) : _name(name) {
        if (grade < HIGHEST_GRADE) {
            throw GradeTooHighException();
        }
        if (grade > LOWEST_GRADE) {
            throw GradeTooLowException();
        }
        _grade = grade;
    }
    
    Bureaucrat::Bureaucrat(const Bureaucrat& other)
        : _name(other._name), _grade(other._grade) {}
    
    Bureaucrat& Bureaucrat::operator=(const Bureaucrat& other) {
        if (this != &other) {
            // _name is const, cannot be assigned
            _grade = other._grade;
        }
        return *this;
    }
    
    Bureaucrat::~Bureaucrat() {}
    
    // ゲッター
    const std::string& Bureaucrat::getName() const {
        return _name;
    }
    
    int Bureaucrat::getGrade() const {
        return _grade;
    }
    
    // グレード操作
    void Bureaucrat::incrementGrade() {
        if (_grade <= HIGHEST_GRADE) {
            throw GradeTooHighException();
        }
        _grade--;
    }
    
    void Bureaucrat::decrementGrade() {
        if (_grade >= LOWEST_GRADE) {
            throw GradeTooLowException();
        }
        _grade++;
    }
    
    // ストリーム演算子
    std::ostream& operator<<(std::ostream& os, const Bureaucrat& bureaucrat) {
        os << bureaucrat.getName() << ", bureaucrat grade " << bureaucrat.getGrade();
        return os;
    }
    
    // main.cpp
    #include "Bureaucrat.hpp"
    
    int main() {
        std::cout << "=== Valid Bureaucrat ===" << std::endl;
        try {
            Bureaucrat bob("Bob", 50);
            std::cout << bob << std::endl;
    
            bob.incrementGrade();
            std::cout << "After increment: " << bob << std::endl;
    
            bob.decrementGrade();
            std::cout << "After decrement: " << bob << std::endl;
        } catch (const std::exception& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    
        std::cout << "\n=== Grade Too High ===" << std::endl;
        try {
            Bureaucrat highBob("HighBob", 0);
        } catch (const std::exception& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    
        std::cout << "\n=== Grade Too Low ===" << std::endl;
        try {
            Bureaucrat lowBob("LowBob", 151);
        } catch (const std::exception& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    
        std::cout << "\n=== Increment at Grade 1 ===" << std::endl;
        try {
            Bureaucrat topBob("TopBob", 1);
            std::cout << topBob << std::endl;
            topBob.incrementGrade();  // throws
        } catch (const std::exception& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    
        return 0;
    }
    

    ---

    2. ex01: Form up, maggots!

    2.1 課題の要件

  • Formクラス(name, signed, gradeToSign, gradeToExecute)
  • beSigned()メソッド
  • Bureaucrat::signForm()メソッド
  • 2.2 Formクラス

    // Form.hpp
    #ifndef FORM_HPP
    #define FORM_HPP
    
    #include <string>
    #include <iostream>
    #include <exception>
    
    class Bureaucrat;
    
    class Form {
    public:
        class GradeTooHighException : public std::exception {
        public:
            const char* what() const throw();
        };
    
        class GradeTooLowException : public std::exception {
        public:
            const char* what() const throw();
        };
    
    private:
        const std::string _name;
        bool _signed;
        const int _gradeToSign;
        const int _gradeToExecute;
    
    public:
        Form();
        Form(const std::string& name, int gradeToSign, int gradeToExecute);
        Form(const Form& other);
        Form& operator=(const Form& other);
        ~Form();
    
        const std::string& getName() const;
        bool isSigned() const;
        int getGradeToSign() const;
        int getGradeToExecute() const;
    
        void beSigned(const Bureaucrat& bureaucrat);
    };
    
    std::ostream& operator<<(std::ostream& os, const Form& form);
    
    #endif
    
    // Form.cpp
    #include "Form.hpp"
    #include "Bureaucrat.hpp"
    
    const char* Form::GradeTooHighException::what() const throw() {
        return "Form grade is too high";
    }
    
    const char* Form::GradeTooLowException::what() const throw() {
        return "Form grade is too low";
    }
    
    Form::Form()
        : _name("Default"), _signed(false), _gradeToSign(150), _gradeToExecute(150) {}
    
    Form::Form(const std::string& name, int gradeToSign, int gradeToExecute)
        : _name(name), _signed(false), _gradeToSign(gradeToSign), _gradeToExecute(gradeToExecute) {
        if (gradeToSign < 1 || gradeToExecute < 1) {
            throw GradeTooHighException();
        }
        if (gradeToSign > 150 || gradeToExecute > 150) {
            throw GradeTooLowException();
        }
    }
    
    Form::Form(const Form& other)
        : _name(other._name),
          _signed(other._signed),
          _gradeToSign(other._gradeToSign),
          _gradeToExecute(other._gradeToExecute) {}
    
    Form& Form::operator=(const Form& other) {
        if (this != &other) {
            _signed = other._signed;
        }
        return *this;
    }
    
    Form::~Form() {}
    
    const std::string& Form::getName() const { return _name; }
    bool Form::isSigned() const { return _signed; }
    int Form::getGradeToSign() const { return _gradeToSign; }
    int Form::getGradeToExecute() const { return _gradeToExecute; }
    
    void Form::beSigned(const Bureaucrat& bureaucrat) {
        if (bureaucrat.getGrade() > _gradeToSign) {
            throw GradeTooLowException();
        }
        _signed = true;
    }
    
    std::ostream& operator<<(std::ostream& os, const Form& form) {
        os << "Form " << form.getName()
           << " [signed: " << (form.isSigned() ? "yes" : "no")
           << ", grade to sign: " << form.getGradeToSign()
           << ", grade to execute: " << form.getGradeToExecute() << "]";
        return os;
    }
    

    2.3 Bureaucrat::signForm()

    // Bureaucrat.hppに追加
    void signForm(Form& form);
    
    // Bureaucrat.cppに追加
    #include "Form.hpp"
    
    void Bureaucrat::signForm(Form& form) {
        try {
            form.beSigned(*this);
            std::cout << _name << " signed " << form.getName() << std::endl;
        } catch (const std::exception& e) {
            std::cout << _name << " couldn't sign " << form.getName()
                      << " because " << e.what() << std::endl;
        }
    }
    

    ---

    3. ex02: No, you need form 28B, not 28C...

    3.1 課題の要件

  • FormをAForm(抽象クラス)に変更
  • 3つの具象Formクラス:
- ShrubberyCreationForm - RobotomyRequestForm - PresidentialPardonForm
  • execute()メソッド
  • 3.2 AFormクラス

    // AForm.hpp
    #ifndef AFORM_HPP
    #define AFORM_HPP
    
    #include <string>
    #include <iostream>
    #include <exception>
    
    class Bureaucrat;
    
    class AForm {
    public:
        class GradeTooHighException : public std::exception {
            const char* what() const throw();
        };
        class GradeTooLowException : public std::exception {
            const char* what() const throw();
        };
        class FormNotSignedException : public std::exception {
            const char* what() const throw();
        };
    
    protected:
        virtual void executeAction() const = 0;
    
    private:
        const std::string _name;
        bool _signed;
        const int _gradeToSign;
        const int _gradeToExecute;
    
    public:
        AForm();
        AForm(const std::string& name, int gradeToSign, int gradeToExecute);
        AForm(const AForm& other);
        AForm& operator=(const AForm& other);
        virtual ~AForm();
    
        const std::string& getName() const;
        bool isSigned() const;
        int getGradeToSign() const;
        int getGradeToExecute() const;
    
        void beSigned(const Bureaucrat& bureaucrat);
        void execute(const Bureaucrat& executor) const;
    };
    
    std::ostream& operator<<(std::ostream& os, const AForm& form);
    
    #endif
    
    // AForm.cpp
    #include "AForm.hpp"
    #include "Bureaucrat.hpp"
    
    const char* AForm::FormNotSignedException::what() const throw() {
        return "Form is not signed";
    }
    
    void AForm::execute(const Bureaucrat& executor) const {
        if (!_signed) {
            throw FormNotSignedException();
        }
        if (executor.getGrade() > _gradeToExecute) {
            throw GradeTooLowException();
        }
        executeAction();
    }
    

    3.3 ShrubberyCreationForm

    // ShrubberyCreationForm.hpp
    #ifndef SHRUBBERYCREATIONFORM_HPP
    #define SHRUBBERYCREATIONFORM_HPP
    
    #include "AForm.hpp"
    #include <fstream>
    
    class ShrubberyCreationForm : public AForm {
    private:
        std::string _target;
    
    protected:
        void executeAction() const;
    
    public:
        ShrubberyCreationForm();
        ShrubberyCreationForm(const std::string& target);
        ShrubberyCreationForm(const ShrubberyCreationForm& other);
        ShrubberyCreationForm& operator=(const ShrubberyCreationForm& other);
        ~ShrubberyCreationForm();
    };
    
    #endif
    
    // ShrubberyCreationForm.cpp
    #include "ShrubberyCreationForm.hpp"
    
    ShrubberyCreationForm::ShrubberyCreationForm()
        : AForm("ShrubberyCreationForm", 145, 137), _target("default") {}
    
    ShrubberyCreationForm::ShrubberyCreationForm(const std::string& target)
        : AForm("ShrubberyCreationForm", 145, 137), _target(target) {}
    
    ShrubberyCreationForm::ShrubberyCreationForm(const ShrubberyCreationForm& other)
        : AForm(other), _target(other._target) {}
    
    ShrubberyCreationForm& ShrubberyCreationForm::operator=(const ShrubberyCreationForm& other) {
        if (this != &other) {
            AForm::operator=(other);
            _target = other._target;
        }
        return *this;
    }
    
    ShrubberyCreationForm::~ShrubberyCreationForm() {}
    
    void ShrubberyCreationForm::executeAction() const {
        std::ofstream file((_target + "_shrubbery").c_str());
        if (!file) {
            throw std::runtime_error("Failed to create file");
        }
        file << "       _-_" << std::endl;
        file << "    /~~   ~~\\" << std::endl;
        file << " /~~         ~~\\" << std::endl;
        file << "{               }" << std::endl;
        file << " \\  _-     -_  /" << std::endl;
        file << "   ~  \\\\ //  ~" << std::endl;
        file << "_- -   | | _- _" << std::endl;
        file << "  _ -  | |   -_" << std::endl;
        file << "      // \\\\" << std::endl;
        file.close();
    }
    

    3.4 RobotomyRequestForm

    // RobotomyRequestForm.hpp
    #ifndef ROBOTOMYREQUESTFORM_HPP
    #define ROBOTOMYREQUESTFORM_HPP
    
    #include "AForm.hpp"
    #include <cstdlib>
    #include <ctime>
    
    class RobotomyRequestForm : public AForm {
    private:
        std::string _target;
    
    protected:
        void executeAction() const;
    
    public:
        RobotomyRequestForm();
        RobotomyRequestForm(const std::string& target);
        RobotomyRequestForm(const RobotomyRequestForm& other);
        RobotomyRequestForm& operator=(const RobotomyRequestForm& other);
        ~RobotomyRequestForm();
    };
    
    #endif
    
    // RobotomyRequestForm.cpp
    #include "RobotomyRequestForm.hpp"
    
    RobotomyRequestForm::RobotomyRequestForm()
        : AForm("RobotomyRequestForm", 72, 45), _target("default") {}
    
    RobotomyRequestForm::RobotomyRequestForm(const std::string& target)
        : AForm("RobotomyRequestForm", 72, 45), _target(target) {}
    
    RobotomyRequestForm::RobotomyRequestForm(const RobotomyRequestForm& other)
        : AForm(other), _target(other._target) {}
    
    RobotomyRequestForm& RobotomyRequestForm::operator=(const RobotomyRequestForm& other) {
        if (this != &other) {
            AForm::operator=(other);
            _target = other._target;
        }
        return *this;
    }
    
    RobotomyRequestForm::~RobotomyRequestForm() {}
    
    void RobotomyRequestForm::executeAction() const {
        std::cout << "* DRILLING NOISES *" << std::endl;
        srand(time(NULL));
        if (rand() % 2) {
            std::cout << _target << " has been robotomized successfully!" << std::endl;
        } else {
            std::cout << "Robotomy on " << _target << " failed." << std::endl;
        }
    }
    

    3.5 PresidentialPardonForm

    // PresidentialPardonForm.hpp
    #ifndef PRESIDENTIALPARDONFORM_HPP
    #define PRESIDENTIALPARDONFORM_HPP
    
    #include "AForm.hpp"
    
    class PresidentialPardonForm : public AForm {
    private:
        std::string _target;
    
    protected:
        void executeAction() const;
    
    public:
        PresidentialPardonForm();
        PresidentialPardonForm(const std::string& target);
        PresidentialPardonForm(const PresidentialPardonForm& other);
        PresidentialPardonForm& operator=(const PresidentialPardonForm& other);
        ~PresidentialPardonForm();
    };
    
    #endif
    
    // PresidentialPardonForm.cpp
    #include "PresidentialPardonForm.hpp"
    
    PresidentialPardonForm::PresidentialPardonForm()
        : AForm("PresidentialPardonForm", 25, 5), _target("default") {}
    
    PresidentialPardonForm::PresidentialPardonForm(const std::string& target)
        : AForm("PresidentialPardonForm", 25, 5), _target(target) {}
    
    PresidentialPardonForm::PresidentialPardonForm(const PresidentialPardonForm& other)
        : AForm(other), _target(other._target) {}
    
    PresidentialPardonForm& PresidentialPardonForm::operator=(const PresidentialPardonForm& other) {
        if (this != &other) {
            AForm::operator=(other);
            _target = other._target;
        }
        return *this;
    }
    
    PresidentialPardonForm::~PresidentialPardonForm() {}
    
    void PresidentialPardonForm::executeAction() const {
        std::cout << _target << " has been pardoned by Zaphod Beeblebrox." << std::endl;
    }
    

    3.6 Bureaucrat::executeForm()

    // Bureaucrat.hppに追加
    void executeForm(const AForm& form);
    
    // Bureaucrat.cppに追加
    void Bureaucrat::executeForm(const AForm& form) {
        try {
            form.execute(*this);
            std::cout << _name << " executed " << form.getName() << std::endl;
        } catch (const std::exception& e) {
            std::cout << _name << " couldn't execute " << form.getName()
                      << " because " << e.what() << std::endl;
        }
    }
    

    ---

    4. ex03: At least this beats coffee-making(Bonus)

    4.1 課題の要件

  • Internクラス
  • makeForm()メソッドでFormを作成
  • 4.2 Internクラス

    // Intern.hpp
    #ifndef INTERN_HPP
    #define INTERN_HPP
    
    #include <string>
    #include "AForm.hpp"
    
    class Intern {
    public:
        Intern();
        Intern(const Intern& other);
        Intern& operator=(const Intern& other);
        ~Intern();
    
        AForm* makeForm(const std::string& formName, const std::string& target);
    
    private:
        AForm* makeShrubbery(const std::string& target);
        AForm* makeRobotomy(const std::string& target);
        AForm* makePardon(const std::string& target);
    };
    
    #endif
    
    // Intern.cpp
    #include "Intern.hpp"
    #include "ShrubberyCreationForm.hpp"
    #include "RobotomyRequestForm.hpp"
    #include "PresidentialPardonForm.hpp"
    
    Intern::Intern() {}
    Intern::Intern(const Intern& other) { (void)other; }
    Intern& Intern::operator=(const Intern& other) { (void)other; return *this; }
    Intern::~Intern() {}
    
    AForm* Intern::makeShrubbery(const std::string& target) {
        return new ShrubberyCreationForm(target);
    }
    
    AForm* Intern::makeRobotomy(const std::string& target) {
        return new RobotomyRequestForm(target);
    }
    
    AForm* Intern::makePardon(const std::string& target) {
        return new PresidentialPardonForm(target);
    }
    
    AForm* Intern::makeForm(const std::string& formName, const std::string& target) {
        std::string formNames[] = {
            "shrubbery creation",
            "robotomy request",
            "presidential pardon"
        };
    
        AForm* (Intern::*formCreators[])(const std::string&) = {
            &Intern::makeShrubbery,
            &Intern::makeRobotomy,
            &Intern::makePardon
        };
    
        for (int i = 0; i < 3; i++) {
            if (formNames[i] == formName) {
                std::cout << "Intern creates " << formName << std::endl;
                return (this->*formCreators[i])(target);
            }
        }
    
        std::cerr << "Intern cannot create form: " << formName << std::endl;
        return NULL;
    }
    
    // main.cpp
    #include "Intern.hpp"
    #include "Bureaucrat.hpp"
    
    int main() {
        Intern someRandomIntern;
    
        AForm* form1 = someRandomIntern.makeForm("shrubbery creation", "home");
        AForm* form2 = someRandomIntern.makeForm("robotomy request", "Bender");
        AForm* form3 = someRandomIntern.makeForm("presidential pardon", "Bob");
        AForm* form4 = someRandomIntern.makeForm("unknown form", "target");
    
        Bureaucrat boss("Boss", 1);
    
        if (form1) {
            boss.signForm(*form1);
            boss.executeForm(*form1);
            delete form1;
        }
    
        if (form2) {
            boss.signForm(*form2);
            boss.executeForm(*form2);
            delete form2;
        }
    
        if (form3) {
            boss.signForm(*form3);
            boss.executeForm(*form3);
            delete form3;
        }
    
        return 0;
    }
    

    ---

    まとめ

    本章で実装した内容:

  • ex00: Bureaucratと基本的な例外処理
  • ex01: Formクラスと署名機能
  • ex02: 抽象Form(AForm)と具象Form
  • ex03: Internによるファクトリパターン