1
\$\begingroup\$

This is a redesign of the class system for a project I started a while ago (I posted about it, but it was really a lot of time ago and the codebase changed so much).

I rewrote this because the previous system was a complete mess with objects that were forced to be allocated dinamically, void pointers, casts, enums, non-smart pointers... that kind of stuff. So I decided to start reading a good book (Effective C++) and this is what I've managed to write.

The code should be pretty straightforward (tell me if it isn't). We have two grand-types of classes: values, which contain a single data attribute, and tokens, which are meant to be convertible to values and contain and additional line member.

Both values and tokens need to contain different types of data (doubles or strings, mostly) and that's why I'm manipulating these via a polyphormic base class (Value::Base and Token::Base).

Tokens can also be of a type, symbol, which shouldn't be convertible to value.

types.hpp:

#pragma once
#include <string>
#include <memory>
#include <list>

namespace Value {
    enum class Type {
        number,
        variable,
        name,
        string
    };

    struct Base {
        Value::Type type;

        virtual ~Base() = default;

        protected:
        Base(const Value::Type &&new_type);
    };

    struct Number: public Value::Base {
        double data;

        Number(const double &new_data);
        ~Number() override = default;
    };

    struct Variable: public Value::Base {
        std::string data;

        Variable(const std::string &new_data);
        ~Variable() override = default;
    };

    struct Name: public Value::Base {
        std::string data;

        Name(const std::string &new_data);
        ~Name() override = default;
    };

    struct String: public Value::Base {
        std::string data;

        String(const std::string &new_data);
        ~String() override = default;
    };

    using Ptr = std::unique_ptr<Value::Base>;
    using List = std::list<Value::Ptr>;
};



namespace Token {
    enum class Type {
        number,
        variable,
        name,
        string,
        symbol
    };

    struct Base {
        Token::Type type;
        const unsigned int line;

        virtual ~Base() = default;

        virtual Value::Ptr to_value() = 0;

        protected:
        Base(const Token::Type &&new_type, const unsigned int &new_line);
    };

    struct Number: public Token::Base {
        double data;

        Number(const double &new_data, const unsigned int &new_line);
        ~Number() override = default;

        Value::Ptr to_value() override;
    };

    struct Variable: public Token::Base {
        std::string data;

        Variable(const std::string &new_data, const unsigned int &new_line);
        ~Variable() override = default;

        Value::Ptr to_value() override;
    };

    struct Name: public Token::Base {
        std::string data;

        Name(const std::string &new_data, const unsigned int &new_line);
        ~Name() override = default;

        Value::Ptr to_value() override;
    };

    struct String: public Token::Base {
        std::string data;

        String(const std::string &new_data, const unsigned int &new_line);
        ~String() override = default;

        Value::Ptr to_value() override;
    };

    struct Symbol: public Token::Base {
        char data;

        Symbol(const char &new_data, const unsigned int &new_line);
        ~Symbol() override = default;

        Value::Ptr to_value() override = 0;
    };

    using Ptr = std::unique_ptr<Token::Base>;
    using List = std::list<Token::Ptr>;
};

types.cpp:

#include "../include/types.hpp"
#include <string>

Value::Base::Base(const Value::Type &&new_type):
    type(new_type) {}

Value::Number::Number(const double &new_data):
    Value::Base(Value::Type::number), data(new_data) {}

Value::Variable::Variable(const std::string &new_data):
    Value::Base(Value::Type::variable), data(new_data) {}

Value::Name::Name(const std::string &new_data):
    Value::Base(Value::Type::name), data(new_data) {}

Value::String::String(const std::string &new_data):
    Value::Base(Value::Type::string), data(new_data) {}



Token::Base::Base(const Token::Type &&new_type, const unsigned int &new_line):
    type(new_type), line(new_line) {}

Token::Number::Number(const double &new_data, const unsigned int &new_line):
    Token::Base(Token::Type::number, new_line), data(new_data) {}

Value::Ptr Token::Number::to_value() {
    return Value::Ptr(new Value::Number(data));
}

Token::Variable::Variable(const std::string &new_data, const unsigned int &new_line):
    Token::Base(Token::Type::variable, new_line), data(new_data) {}

Value::Ptr Token::Variable::to_value() {
    return Value::Ptr(new Value::Variable(data));
}

Token::Name::Name(const std::string &new_data, const unsigned int &new_line):
    Token::Base(Token::Type::name, new_line), data(new_data) {}

Value::Ptr Token::Name::to_value() {
    return Value::Ptr(new Value::Name(data));
}

Token::String::String(const std::string &new_data, const unsigned int &new_line):
    Token::Base(Token::Type::string, new_line), data(new_data) {}

Value::Ptr Token::String::to_value() {
    return Value::Ptr(new Value::String(data));
}

Token::Symbol::Symbol(const char &new_data, const unsigned int &new_line):
    Token::Base(Token::Type::symbol, new_line), data(new_data) {}

I especially need advice on polyphormy, virtual functions and the like because this is the first time I use these features, but don't be afraid of pointing out whatever advice on different subjects to make my code better.

\$\endgroup\$
4
  • \$\begingroup\$ You can check under your summary in your profile to link the old post to this one as its a continuation right? \$\endgroup\$ – Tolani Nov 3 '16 at 18:43
  • \$\begingroup\$ @Tolani Jaiye-Tikolo not entirely. That one was the class system (which was a lot smaller) + the first part of the code. This post instead is only focused on the class system, which has changed a lot from that post to what it was before this redesign and changed even more with this redesign. \$\endgroup\$ – user6245072 Nov 3 '16 at 18:47
  • \$\begingroup\$ What is the reason for using struct's instead of classes? \$\endgroup\$ – Attilio Nov 3 '16 at 19:21
  • 1
    \$\begingroup\$ @Attilio I don't have a real reason. I mostly use public members so using class is just more typing, and I am also just storing data with little to no operations on it, so the struct seemed more appropriate to me. \$\endgroup\$ – user6245072 Nov 3 '16 at 19:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.