Narek
Narek

Reputation: 39881

Inheritance and small number of parameters

Uncle Bob in his Clean Code suggests that no more than 3 arguments should a function get:

Functions that take three arguments are significantly harder to understand than dyads. The issues of ordering, pausing, and ignoring are more than doubled. I suggest you think very carefully before creating a triad.

But what about CTOR arguments in class inheritance hierarchy? What if each class in hierarchy adds a new field and you should initialize them in CTOR. See an example below:

class Person
{
private:
    std::string m_name;
    int m_age;

public:
    Person(const std::string& name, const int age);
    std::string getName() const { return m_name; }
    int getAge() const { return m_age; }
    ~Person();
};


class Student : public Person
{
private:
    std::string m_university;
    int m_grade;

public:
    Student(const std::string& name, const int age, const std::string& university, const int grade);
    std::string getUniversity() const { return m_university; }
    int getGrade() const { return m_grade; }
    ~Student();
};

See how Student gets 4 arguments, while Person gets only 2 and Student adds two more. So how we should handle this?

Upvotes: 2

Views: 68

Answers (3)

MSalters
MSalters

Reputation: 179991

You're confusing two distinct meanings of the word function.

The first meaning is more related to the original mathematical meaning of the word. In this case, function is a named relation between one or more inputs and exactly one output. The "Clean Code" rules refers to this meaning, and tells you that more should be limited to 3 inputs.

The alternative meaning in C++ refers to a block of code, which may or may have inputs, which may or may have an output, which may or may have a name.

And yes, even in the latter sense, constructors are unusual functions. They never have a return type, not even void, and they don't have names. So you can rationalize that they're also special when it comes to their number of input arguments.

Upvotes: 0

fgrdn
fgrdn

Reputation: 91

i'd say this was just a suggestion. it's fully up to you - how many arguments should your functions get.

but if you prefer to follow the rule, make some sort of parameters holder, like:

class Student
{
  public:
    struct StudentParameters
    {
      ...
    };
    Student(name, age, const StudentParameters &sp);
...
};

Upvotes: 1

for_stack
for_stack

Reputation: 22981

There are several ways.

Combine multiple parameters into a struct

struct PersonInfo {
    std::string name;
    int age;
};

struct StudentInfo {
    PersonInfo person_info;
    std::string university;
    int grade;
};

Person::Person(const PersonInfo &info) :m_name(info.name), m_age(info.age) {}
Student::Student(const StudentInfo &info) : Person(info.person_info), m_university(info.university), m_grade(info.grade) {}

Default initialize data members and set them with setter utilities

Person::Person() : m_age(0) {}
void Person::set_age(int age) { m_age = age; }

Student() : m_grade(0) {} // Person is default constructed.
void Student::set_grade(int grade) { m_grade = grade; }

Upvotes: 4

Related Questions