使用一个函数调用 C++ 初始化多个常量类成员

Qq0*_*Qq0 52 c++ oop constructor constants initializer-list

如果我有两个不同的常量成员变量,它们都需要基于相同的函数调用进行初始化,有没有办法在不调用函数两次的情况下做到这一点?

例如,分子和分母是常数的分数类。

int gcd(int a, int b); // Greatest Common Divisor
class Fraction {
public:
    // Lets say we want to initialize to a reduced fraction
    Fraction(int a, int b) : numerator(a/gcd(a,b)), denominator(b/gcd(a,b))
    {

    }
private:
    const int numerator, denominator;
};
Run Code Online (Sandbox Code Playgroud)

这会浪费时间,因为 GCD 函数被调用了两次。您还可以定义一个新的类成员 ,gcd_a_b然后首先将 gcd 的输出分配给初始化列表中的那个,但这会导致浪费内存。

一般来说,有没有办法在不浪费函数调用或内存的情况下做到这一点?您可以在初始化列表中创建临时变量吗?

Dre*_*ann 69

一般来说,有没有办法在不浪费函数调用或内存的情况下做到这一点?

是的。这可以通过C++11 中引入的委托构造函数来完成。

委托构造函数是在初始化任何成员变量之前获取构造所需的临时值的一种非常有效的方法。

int gcd(int a, int b); // Greatest Common Divisor

class Fraction {
public:
    // Call gcd ONCE, and forward the result to another constructor.
    Fraction(int a, int b) : Fraction(a,b,gcd(a,b))
    {
    }
private:
    // This constructor is private, as it is an
    // implementation detail and not part of the public interface.
    Fraction(int a, int b, int g_c_d) : numerator(a/g_c_d), denominator(b/g_c_d)
    {
    }
    const int numerator, denominator;
};
Run Code Online (Sandbox Code Playgroud)

  • @Qq0:C++ 是围绕现代优化编译器设计的。他们可以轻松地内联此委托,特别是如果您使其在类定义中(在“.h”中)可见,即使真正的构造函数定义对于内联不可见。即“gcd()”调用将内联到每个构造函数调用点,并只为 3 操作数私有构造函数留下一个“call”。 (2认同)

asm*_*mmo 10

成员变量按它们在类声明中声明的顺序进行初始化,因此您可以执行以下操作(数学上)

#include <iostream>
int gcd(int a, int b){return 2;}; // Greatest Common Divisor of (4, 6) just to test
class Fraction {
public:
    // Lets say we want to initialize to a reduced fraction
    Fraction(int a, int b) : numerator{a/gcd(a,b)}, denominator(b/(a/numerator))
    {    
    }
//private:
    const int numerator, denominator;//make sure that they are in this order
};
//Test
int main(){
    Fraction f{4,6};
    std::cout << f.numerator << " / " << f.denominator;
}
Run Code Online (Sandbox Code Playgroud)

不需要调用另一个构造函数,甚至不需要创建它们。

  • 好的,这特别适用于 GCD,但是许多其他用例可能无法从 args 和第一个 const 派生出第二个 const。正如所写的,这有一个额外的除法,这是编译器可能无法优化掉的另一个缺点。GCD 可能只花费一个除法,所以这可能几乎和调用 GCD 两次一样糟糕。(假设除法主导其他操作的成本,就像现代 CPU 上经常发生的那样。) (6认同)