具有成员函数的 C++ 结构与具有公共变量的类

2021-12-23 00:00:00 class struct c++

这确实是一个关于良好形式/最佳实践的问题.我在 C++ 中使用结构来形成旨在基本上保存数据的对象,而不是使用大量访问器方法创建一个类,这些访问器方法除了获取/设置值之外什么都不做.例如:

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;
    (...)
};

如果你想象那里有 20 个以上的变量,把它写成一个包含私有成员和 40 多个访问器的类是很难管理的,对我来说似乎很浪费.

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.

有时,我可能还需要向数据添加某种最小功能.在示例中,假设我有时也需要年龄,基于 dob:

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.

推荐答案

我认为这里有两个重要的设计原则需要考虑:

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

  1. 如果该类有一些不变性,则通过接口隐藏该类的表示.

当该类存在无效状态时,该类具有不变量.类应始终保持不变.

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.

考虑表示二维几何点的 Point 类型.这应该只是一个带有公共 xy 数据成员的 struct.没有无效点这样的东西.xy 值的每个组合都非常好.

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.

对于Person,它是否有不变量完全取决于手头的问题.您认为空名称之类的东西是有效名称吗?Person 可以有任何出生日期吗?对于你的情况,我认为答案是肯定的,你的班级应该让成员公开.

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.

参见:类应该强制执行不变量

非友元非成员函数改进封装.

没有理由将您的 age 函数实现为成员函数.age的结果可以通过Person的公共接口计算出来,所以没有理由成为成员函数.将它放在与 Person 相同的命名空间中,以便通过依赖于参数的查找找到它.ADL 找到的函数是该类接口的一部分;他们只是无权访问私人数据.

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.

如果您确实将其设为成员函数,并且有一天向Person 引入了一些私有状态,那么您将拥有不必要的依赖项.突然 age 获得了比它需要的更多的数据访问权限.

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.

参见:非成员函数如何改进封装p>

所以这是我将如何实现它:

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;
}

相关文章