Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Should this class have a user provided constructor?

I would like to parse some command-line arguments and depending of the input to create objects of some class type. For example:

./myprogram --save --secret <secret> --name <name> --username <username> --password <password> --group <group>

For this kind of input I want to create an object of class SaveOption.

I am thinking of defining it like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class VaultEntry
{
public:
    VaultEntry() = default;
    VaultEntry(std::string_view usernmae, std::string_view password std::string_view group);
    VaultEntry(std::string_view usernmae, std::string_view password std::string&& group);
    VaultEntry(std::string_view usernmae, std::string&& password std::string_view group);
    VaultEntry(std::string&& usernmae, std::string_view password std::string_view group);
    VaultEntry(std::string_view usernmae, std::string&& password std::string&& group);
    VaultEntry(std::string&& usernmae, std::string_view password std::string&& group);
    VaultEntry(std::string&& usernmae, std::string&& password std::string_view group);
    VaultEntry(std::string&& usernmae, std::string&& password std::string&& group);

    std::string_view Username() const noexcept;
    void Username(std::string_view username);
    void Username(std::string&& username);

    std::string_view Password() const noexcept;
    void Password(std::string_view password);
    void Password(std::string&& password);

    std::string_view Group() const noexcept;
    void Group(std::string_view group);
    void Group(std::string&& group);
private:
    std::string m_Username;
    std::string m_Password;
    std::string m_Group;
};

class SaveOption
{
public:
    SaveOption() = default;
    SaveOption(std::string_view secret, const VaultEntry& entry);
    SaveOption(std::string&& secret, VaultEntry&& entry);
    SaveOption(std::string_view secret, VaultEntry&& entry);
    SaveOption(std::string&& secret, const VaultEntry& entry);

    std::string_view Secret() const noexcept;
    void Secret(std::string_view secret);
    void Secret(std::string&& secret);

    const VaultEntry& Entry() const noexcept;
    void Entry(const VaultEntry& entry);
private:
    std::string m_Secret;
    VaultEntry m_VaultEntry;
};

However, I am bothered by the big number of constructors. If I had only a constructor with only std::string_view parameters, it would not take into account the situations when I can move the std::string.

Do you think that it will be better if I define this kind of classes as aggregates?

struct VaultEntry
{
    std::string username;
    std::string password;
    std::string group;
};

struct SaveOption
{
    std::string secret;
    VaultEntry entry;
};

Of define them as aggregates, but the types of the non-static data members are more representative?

class Username
{
    Username() = default;
    Username(std::string_view username);
    Username(std::string&& username);
    operator string_view() const noexcept;
private:
    std::string m_Username;
};

class Password
{
    Password() = default;
    Password(std::string_view password);
    Password(std::string&& password);
    operator string_view() const noexcept;
private:
    std::string m_Password;
};

class Group
{
    Group() = default;
    Group(std::string_view group);
    Group(std::string&& group);
    operator string_view() const noexcept;
private:
    std::string m_Group;
};

struct VaultEntry
{
    Username username;
    Password password;
    Group group;
};

class Secret
{
    Secret() = default;
    Secret(std::string_view secret);
    Secret(std::string&& secret);
    operator string_view() const noexcept;
private:
    std::string m_Secret;
};

struct SaveOption
{
    Secret secret;
    VaultEntry entry;
};

I defined the non-explicit conversion operator, because I think it will help me later when I serialize the data or print information for debugging purposes. Of course, if you have another opinion, I would like to hear it.

I would like to ask for the input of more experienced C++ developers. What design choice do you think is better? Can I improve it?

I need your input because I would like to add this project to my portofolio and I need to use modern C++ with good design.

Thank you!

>Solution :

Absent of any context about usage, it’s hard to make a recommendation. I’d lean toward the simplest:

struct VaultEntry
{
    std::string username;
    std::string password;
    std::string group;
};

struct SaveOption
{
    std::string secret;
    VaultEntry entry;
};

Having every combination of constructors for multiple parameters is awful. If you did want a non-aggregate type, the constructors should take by value, and move into the data member. At worst you are doing one extra move per string, which is really cheap.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading