【问题标题】:Accessing value using get method or member directly?直接使用 get 方法或成员访问值?
【发布时间】:2014-08-25 16:57:53
【问题描述】:
class SomeClass
{
    int classMember;
    public:
    int GetMember();
    bool IsPositive();
};

int SomeClass::GetMember()
{
   return classMember;
}

bool SomeClass::IsPositive()
{
    int val = GetMember();  //Case#1. Accessing value using get method
    int val = classMember;  //Case#2. Accessing value directly

    return (val > 0);
}

问题:使用案例#1 是否比案例#2 有任何优势,反之亦然?与直接使用成员相比,使用 get 方法是否有任何开销(即使是最小的)?

【问题讨论】:

  • 调用getter函数可能有一些微小的开销,因为除了访问成员变量之外,还需要构造函数并将其扔到堆栈上。此外,您应该只使用return (val > 0);,而不是您在那里占用 6 行的喧嚣。
  • 给定一个合理的编译器,执行时应该没有开销。但是,缺乏可读性会带来更大的开销。
  • 拆开看看就知道了……
  • @Jerry Coffin 我同意。 return (classMember > 0);return (GetMember() > 0); 更具可读性
  • 这只是冰山一角。考虑将两个数字相加:a.member = b.member + c.membera.set_member(b.get_member() + c.get_member())——甚至是 a.set_member(b.add_values(b.get_member(), c.get_member())

标签: c++ function class member


【解决方案1】:

答案是,这实际上取决于您的编译器选择如何做某事。查看是否有差异的最好方法是查看反汇编。

    int val = classMember;
010C4869  mov         eax,dword ptr [this]  
010C486C  mov         ecx,dword ptr [eax]  
010C486E  mov         dword ptr [val],ecx  

    return val > 0;
010C4871  cmp         dword ptr [val],0  
010C4875  jle         SomeClass::IsPositiveClassMember+20h (010C4880h)  
010C4877  mov         dword ptr [ebp-4],1  
010C487E  jmp         SomeClass::IsPositiveClassMember+27h (010C4887h)  
010C4880  mov         dword ptr [ebp-4],0  
010C4887  mov         al,byte ptr [ebp-4]

对比

    int val = GetMember();
010C4829  mov         ecx,dword ptr [this]  
010C482C  call        SomeClass::GetMember (010C1168h)  
010C4831  mov         dword ptr [val],eax  

    return val > 0;
010C4834  cmp         dword ptr [val],0  
010C4838  jle         SomeClass::IsPositiveGetMember+23h (010C4843h)  
010C483A  mov         dword ptr [ebp-4],1  
010C4841  jmp         SomeClass::IsPositiveGetMember+2Ah (010C484Ah)  
010C4843  mov         dword ptr [ebp-4],0  
010C484A  mov         al,byte ptr [ebp-4]  

第二个例子调用SomeClass::GetMember,它有自己的反汇编。所以在第二种情况下,它不是仅仅从成员中加载值,而是进行函数调用。

    return classMember;
010C4817  mov         eax,dword ptr [this]  
010C481A  mov         eax,dword ptr [eax]  

您会注意到使用 classMember 的值加载 val 的指令是相同的,因此开销来自 Call SomeClass::GetMember

这是在debug 模式下,但是没有优化。如果我们优化并构建发布,我们会看到以下反汇编:

    int val = classMember;

    return val > 0;
013D4830  xor         eax,eax  
013D4832  cmp         dword ptr [ecx],eax  
013D4834  setg        al  

    int val = GetMember();

    return val > 0;
013D4820  xor         eax,eax  
013D4822  cmp         dword ptr [ecx],eax  
013D4824  setg        al  

编译器优化掉调用,没有区别。

【讨论】:

  • 这个答案已经有一个小时了,除了我的以外没有其他人赞成?异端。
【解决方案2】:

这完全取决于程序员的需要。

什么时候创建函数?

  1. 增加程序的模块化
  2. 重复执行某些常见任务时。

在您的情况下,假设要添加两个数字。

你可以使用

int a= data member 1 + data member 2

假设您必须在许多地方使用它。

那么你已经考虑了第 2 点。

您可以只创建像addnumber() 这样的函数,以便于使用和阅读。

关于性能,

两者是相同的,因为 member function are inline by default 在类定义中定义时。所以调用该函数不需要单独的堆栈分配

【讨论】:

    【解决方案3】:

    使用 GetMember() 可能会慢一些,除非它被编译器显式或隐式地内联。

    但是,使用访问器可以极大地帮助您进行调试,暂时改变这一点:

    int SomeClass::GetMember()
    {
       return classMember;
    }
    

    进入这个:

    int SomeClass::GetMember()
    {
       std::cout << "GetMember() called when classMember=" << classMember << std::endl;
       return classMember;
    }
    

    但这可能有点老套了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-24
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 2017-08-24
      • 1970-01-01
      相关资源
      最近更新 更多