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

时间:2013-03-22 14:21:19

标签: c++ class struct

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

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

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

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

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

当然,对于任何复杂的功能,我都会创建一个类,但对于这样一个简单的功能,这是“糟糕的设计”吗?如果我确实使用了一个类,那么将数据变量保存为公共类成员是不好的形式,还是只需要接受它并使用一堆访问器方法创建类?我理解类和结构之间的差异,我只是询问最佳实践。

7 个答案:

答案 0 :(得分:22)

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

  1. 如果该类中存在某些不变量,则通过界面隐藏类的表示。

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

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

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

    请参阅:Classes Should Enforce Invariants

  2. 非朋友非会员功能改善了封装。

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

    如果您确实将其设为成员函数,并且有一天将某个私有状态引入Person,那么您将具有不必要的依赖性。突然age可以访问超出需要的数据。

    请参阅:How Non-Member Functions Improve Encapsulation

  3. 所以我将如何实现它:

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

答案 1 :(得分:6)

在C ++中,Structs是类,只有 的区别(至少我可以想到)是Structs中的成员默认是公共的,但在类中它们是私有的。这意味着使用Structs是完全可以接受的 - this article很好地解释了它。

答案 2 :(得分:1)

在C ++中,结构和类之间的唯一区别是默认情况下结构是公开可见的。一个好的指导方针是使用结构作为普通旧数据(POD),它只保存数据并在需要更多功能(成员函数)时使用类。

您可能仍然想知道是否只在类中使用公共变量或使用成员函数;请考虑以下情况。

假设您有一个类A,其函数GetSomeVariable仅仅是私有变量的getter:

class A
{
    double _someVariable;

public:
    double GetSomeVariable() { return _someVariable; }
};

如果在20年后,该变量的含义发生变化,你必须将它乘以0.5,怎么办呢?使用吸气剂时,很简单;只返回变量乘以0.5:

    double GetSomeVariable() { return 0.5*_someVariable; }

通过这样做,您可以轻松维护,并且可以轻松修改。

答案 3 :(得分:1)

如果你想要一些数据持有者,那么更喜欢没有任何get / set方法的struct。

如果还有更多内容,就像本案例“人”一样。

  1. 它模拟现实世界的实体,
  2. 有明确的状态和行为,
  3. 与外部世界互动,
  4. 与其他实体展示简单/复杂的关系,
  5. 它可能会超时发展,
  6. 那么它是一个完美的候选人。

答案 4 :(得分:0)

"仅将结构用于携带数据的被动对象;其他一切都是一个班级。"

google guidlines,我这样做,并认为这是一个很好的规则。除此之外,我认为您可以定义自己的语用学,或者如果它真的有意义,则偏离此规则。

答案 5 :(得分:0)

我不想在这里发动圣战;我通常以这种方式区分它:

  • 对于POD对象(即仅数据,没有暴露行为)声明内部公共并直接访问它们。这里使用struct关键字很方便,也可以作为对象使用的提示。
  • 对于非POD对象,声明内部私有并定义公共getter / setter。在这些情况下,class关键字的使用更为自然。

答案 6 :(得分:0)

为了消除一些人的困惑!而且采摘方便!这里有几点!

结构中!您可以拥有封装可见性运算符(使私有公开)!就像上课一样!

所以有人说或者你可能在网上找到的说法是:区别之一是结构没有可见性运算符和隐藏数据的能力,是错误的!

你可以像在类中一样拥有方法!

运行下面的代码!你可以检查它编译得很好!并且一切顺利!整个struct就像class一样工作!

主要区别在于可见性模式的默认设置!

结构公开了!默认为私有类!

#include<iostream>
#include<string>

using namespace std;

int main(int argv, char * argc[]) {
    struct {
        private:
            bool _iamSuperPrivate = true;
            void _sayHallo() {
                cout << "Hallo mein Bruder!" << endl;
            }
        public:
            string helloAddress = "";
            void sayHellow() {
                cout << "Hellow!" << endl;
                
                if (this->helloAddress != "") {
                    cout << this->helloAddress << endl;
                }

                this->_sayHallo();
            }
            bool isSuperPrivateWorking() {
                return this->_iamSuperPrivate;
            }
    } testStruct;

    testStruct.helloAddress = "my Friend!";
    testStruct.sayHellow();

    if (testStruct.isSuperPrivateWorking()) {
        cout << "Super private is working all well!" << endl;
    } else {
        cout << "Super private not working LOL !!!" << endl;
    }

    return 0;
}

IC IVAU

在内存中它们是相同的!

我没有检查自己!但有人说,如果你做同样的事情! 结构之间编译后的汇编代码是一样的! (待查!)

选择任何类并将名称更改为 typedef struct !您会看到代码仍然可以正常工作!

class Client {

}

Client client(...);

=>

typedef struct Client {
 ....
} Client;

Client client(...);

如果你这样做,一切都会一样!至少我知道在 gcc 中是这样的!

你可以测试!在您的平台上!