【问题标题】:Creating an object as a private member variable vs. in a member function将对象创建为私有成员变量与在成员函数中
【发布时间】:2015-07-01 07:12:54
【问题描述】:

在类声明中将对象创建为私有成员变量与在类的方法定义中创建对象有什么区别?我知道明显的区别是一个是全局变量,另一个是局部变量。什么情况下应该做前者和后者?

Aclass.h

class Aclass{ 
private: 
    AnotherClass someobj1; //option 1
public:  
    void someMethod(); 
};

Aclass.cpp

void Aclass::someMethod(){ 
    AnotherClass someobj2; //option 2 
}

【问题讨论】:

  • 如果你在类的多个函数中需要它,你应该将它声明为一个私有变量。如果您只在该函数中需要它,则应在该函数中声明它。
  • @Robin 非常感谢。 :)

标签: c++ oop object private-members member-functions


【解决方案1】:

someobj1 确实是一个成员变量。这意味着AClass 的每个实例包含一个名为someobj1 的AnotherClass 实例,该实例与它所属的实例具有相同的生命周期。

someobj2 是someMethod 函数的局部变量。它将在所述函数结束时被销毁。

它们都不是全局的。也许您将它们与具有静态生命周期的 static 成员变量混合在一起(在 main 开始之前构建,在结束之后销毁),就像全局变量一样(但它们并不完全是全局变量,因为它们'被包含在类'范围内。

这里有一个愚蠢的例子来说明问题:

CatBasket gCatBasket; // All cats in the house share the same basket (global)

class Cat {
    Tail _tail; // The tail is part of the cat (member)
    Human *_owner; // The cat remembers his owner for his whole life (member)

    void meow() {
        MeowSound sound; // The "meow" sound only exists while the cat is meowing. (local)
        sound.setAmplitude(17.0f);
        sound.setPurr(true);

        sound.play();
    }

    static bool _beACat;
};

bool Cat::_beACat = true; // Everybody wants to be a cat (static)

【讨论】:

  • 顺便说一句,保持变量的范围尽可能小(封装)是一种很好的做法。因此,如果选项 2 可行,它是首选。
  • @CoertMetz 对于您的代码来说,这是一条非常健康的经验法则,但主要适用于局部变量。成员变量有理由成为成员:它们的生命周期必须与对象相匹配,它们在概念上是对象的一部分......做最有意义的事情:)
  • 非常正确。此外,所有成员变量都确定对象的状态。如果给定的成员变量应该是该状态的一部分似乎不合逻辑,则最好使用局部变量。换句话说,如果成员变量的不同值对应于建模世界中不同的可感知对象,则成为成员变量是有意义的。当然,成员变量还有其他用途,例如出于缓存目的,但我认为这是一个很好的经验法则。
  • @CoertMetz 对我来说听起来很完美!
【解决方案2】:

成员变量(无论其可见性如何)贯穿实例的整个生命周期。只要您有AClass 的实时实例,它将保留someobj1 的值。这些类型的变量(传统上)用于保存对象的状态,您希望将其从一种用法保留到另一种用法。

在方法中定义的局部变量就是一个 local 变量。它是一个辅助变量,帮助你执行方法的功能,一旦方法调用结束就没有意义(也不存在)。

【讨论】:

    【解决方案3】:

    最重要的区别在于您的 AnotherClass 实例的生命周期。

    Aclass.h

    class Aclass{ 
    private: 
        AnotherClass someobj1; //option 1: This instance is accessible from within the Aclass instance as long as the Aclass instance is not destroyed.
    public:  
        void someMethod(); //option 1: So someobj1 is available (for reading AND writing in this method. When you call this method twice, you will work with the same instance each time.
        void someMethodToo(); //option 1: someobj1 will also be available in this method for reading AND writing.
    };
    

    Aclass.cpp

    void Aclass::someMethod(){ 
        AnotherClass someobj2; //option 2: This instance is destroyed when someMethod is done. The method someMethodToo that I described above will never have access to someobj2 either. If you call someMethod twice, each will have it's own someobj2. 
    }
    

    【讨论】:

      【解决方案4】:

      我们可以使用对象作为私有成员来定义Association、Composition和Aggregation等概念。

      考虑以下代码sn-p:

      //ASSOCIATION
      class Bar
      {
          Baz baz;
      };
      class Foo
      {
          Bar* bar;
          void setBar(Bar* _bar)
          {
              bar=_bar;
          }
      };
      
      //AGGREGATION
      class Bar
      {
          Baz baz;
      };
      
      class Foo
      {
          Bar* bar;
          void setBar(Bar* _bar)
          {
              bar = new Bar;
              bar->baz=_bar->baz;
          }
      };
      
      
      //COMPOSTION
      class Bar
      {
          Baz baz;
      };
      class Foo
      {
          Bar bar;
      }
      

      我的理解是:

      1. 关联:Foo 有一个指向 Bar 对象的指针作为数据成员
      2. 聚合:Foo 有一个指向 Bar 对象的指针,并且 Bar 的数据被深度复制到该指针中。
      3. 组合:Foo 有一个 Bar 对象作为数据成员。

      但是,只要对象的使用时间较短(而不是包含它的对象的整个生命周期),就需要第二种用法(成员函数定义中的对象创建)。

      另一个区别是关于内存的:

      作为数据成员的对象将被分配内存并保留到 对象死亡。但是,对象作为成员中的变量 函数将被分配内存并在任何时候释放 函数超出范围。

      【讨论】:

        【解决方案5】:

        编程的绝对规则是在绝对必要时定义、声明或初始化某些东西。这意味着它显然会降低内存和性能的成本。
        也就是说,当您在类中声明成员变量时,每当创建新对象时都会为其分配内存空间。因此,除非您在每个对象中都需要它,否则不要在类范围内声明它。
        当您不希望任何函数或类访问此变量时,再次声明变量私有是必要的。否则,您应该将其公开。
        如果在函数作用域中定义变量,那么只有在函数调用时才会占用内存,函数作用域一结束就会被删除。
        总体而言,类的定义是将数据和与该数据相关的函数保存在一起。因此,当您定义一个类时,您应该记住该类中将存在哪些数据,然后声明将处理数据的函数。
        该功能基本上是在该输入上获取一些输入和处理。最后返回一些必要的数据。如果您需要为要完成的过程声明一些变量,那么只需声明变量即可。

        【讨论】:

          猜你喜欢
          • 2020-03-22
          • 1970-01-01
          • 2016-10-04
          • 2019-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多