Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
516 views
in Technique[技术] by (71.8m points)

class - C++ Structs with Member Functions vs. Classes with Public Variables

This is really a question of good form/best practices. I use structs in C++ to form objects that are designed to basically hold data, rather than making a class with a ton of accessor methods that do nothing but get/set the values. For example:

struct Person {
    std::string name;
    DateObject dob;
    (...)
};

If you imagine 20 more variables there, writing this as a class with private members and 40-something accessors is a pain to manage and seems wasteful to me.

Sometimes though, I might need to also add some sort of minimal functionality to the data. In the example, say I also sometimes need the age, based on dob:

struct Person {
    std::string name;
    DateObject dob;
    (...)
    int age() {return calculated age from dob;}
}

Of course for any complex functionality I would make a class, but for just a simple functionality like this, is this "bad design"? If I do use a class, is it bad form to keep the data variables as public class members, or do I just need to accept it and make classes with a bunch of accessor methods? I understand the differences between classes and structs, I'm just asking about best practices.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think there are two important design principles to consider here:

  1. Hide a class's representation through an interface if there is some invariant on that class.

    A class has an invariant when there is such thing as an invalid state for that class. The class should maintain its invariant at all times.

    Consider a Point type that represents a 2D geometric point. This should just be a struct with public x and y data members. There is no such thing as an invalid point. Every combination of x and y values is perfectly fine.

    In the case of a Person, whether it has invariants depends entirely on the problem at hand. Do you consider such things as an empty name as a valid name? Can the Person have any date of birth? For your case, I think the answer is yes and your class should keep the members public.

    See: Classes Should Enforce Invariants

  2. Non-friend non-member functions improve encapsulation.

    There's no reason your age function should be implemented as a member function. The result of age can be calculated using the public interface of Person, so it has no reason to be a member function. Place it in the same namespace as Person so that it is found by argument-dependent lookup. Functions found by ADL are part of the interface of that class; they just don't have access to private data.

    If you did make it a member function and one day introduced some private state to Person, you would have an unnecessary dependency. Suddenly age has more access to data than it needs.

    See: How Non-Member Functions Improve Encapsulation

So here's how I would implement it:

struct Person {
  std::string name;
  DateObject dob;
};

int age(const Person& person) {
  return calculated age from person.dob;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...