创建一个从其他类成员自动计算的类成员?

时间:2017-07-18 16:35:49

标签: c++ class

  1. 在编程方面,我是一个绝对的新手,而我正试图通过解决C ++中的一些简单“问题”来自学基础知识。

  2. 我已经在网上搜索了我的问题的确切答案,然后在此发布并且到目前为止还没找到,但这可能是因为(1)。

  3. 所以,我正在寻找的是一种声明一个类成员的方法,该类成员可以从同一个类的其他成员自动计算,因此计算出来的类成员可以像显式定义的类成员一样使用。例如,想象一个名为creature的结构,它具有属性/ members creature.numberofhands,creature.fingersperhand,最后是属性creature.totalfingers,它们会自动从上面的成员中计算出来。

    这是我最接近我想达到的目标的一个例子:

    #include <iostream>
    
    typedef struct creature {
        int numberofhands;
        int fingersperhand;
        int totalfingers();
    } creature;    
    
    int creature::totalfingers()
    {
        return numberofhands * fingersperhand;
    };
    
    int main()
    {
        creature human;
        human.numberofhands = 2;
        human.fingersperhand = 5;
    
        printf("%d",human.totalfingers());
        return(0);
    }
    

    对我来说真正令我烦恼的是,我必须从明确定义的那个处理不同的计算方法,即我必须在它之后加上“()”。 如何更改代码,以便我可以使用:human.totalfingers而无需明确定义它?

5 个答案:

答案 0 :(得分:5)

最简单的选择是使用公共成员函数并隐藏实际属性。 像这样:

class Creature {
public:
    Creature(int numhands, int fingersperhand) // constructor
        : m_numhands{numhands}, m_fingersperhand{fingersperhand}
        { }
    int fingersPerHand() const { return m_fingersperhand; }
    int numberOfHands() const { return m_numhands; }
    int totalFingers() const { return numberOfHands() * fingersPerHand(); }

private:
    const int m_numhands;
    const int m_fingersperhand;
};

私有成员变量是一个实现细节。该类用户只需使用三个公共成员函数即可在构造后获得不同数量的手指,并且不需要关心其中两个手指返回常量存储的数字,而第三个返回计算值 - 即&#39;与用户无关。

使用示例:

#include <iostream>
int main()
{
    Creature human{2, 5};
    std::cout << "A human has "
        << human.totalFingers() << " fingers. "
        << human.fingersPerHand() << " on each of their "
        << human.numberOfHands() << " hands.\n";
    return 0;
}

如果 - 根据您的评论 - 您不想使用构造函数(尽管这是确保您不要忘记初始化的最安全的方法成员),您可以像这样修改类:

class CreatureV2 {
public:
    int fingersPerHand() const { return m_fingersperhand; }
    int numberOfHands() const { return m_numhands; }
    int totalFingers() const { return numberOfHands() * fingersPerHand(); }

    void setFingersPerHand(int num) { m_fingersperhand = num; }
    void setNumberOfHands(int num) { m_numhands = num; }

private:
    // Note: these are no longer `const` and I've given them default
    // values matching a human, so if you do nothing you'll get
    // human hands.
    int m_numhands = 2;
    int m_fingersperhand = 5;
};

修改类的使用示例:

#include <iostream>
int main()
{
    CreatureV2 human;
    std::cout << "A human has "
        << human.totalFingers() << " fingers. "
        << human.fingersPerHand() << " on each of their "
        << human.numberOfHands() << " hands.\n";

    CreatureV2 monster;
    monster.setFingersPerHand(7);
    monster.setNumberOfHands(5);
    std::cout << "A monster has "
        << monster.totalFingers() << " fingers. "
        << monster.fingersPerHand() << " on each of their "
        << monster.numberOfHands() << " hands.\n";

    CreatureV2 freak;
    freak.setFingersPerHand(9);
    // Note: I forgot to specify the number of hands, so a freak get 
    // the default 2.
    std::cout << "A freak has "
        << freak.totalFingers() << " fingers. "
        << freak.fingersPerHand() << " on each of their "
        << freak.numberOfHands() << " hands.\n";

    return 0;
}

注意:以上所有假设您使用的是现代C ++ 14编译器。

答案 1 :(得分:2)

您所描述的是封装和&#34;成员变量应该是私有的原因之一&#34;是C ++中推荐的做事方式。

如果通过函数访问每个变量,那么一切都是一致的,并且可以从成员变量重构为计算。

某些语言,如C#或D,具有&#34; properties&#34;的概念,它提供了解决问题的方法,但C ++没有这样的结构。

答案 2 :(得分:2)

为了好玩,避免额外括号的代理方式(但需要一些额外费用):

class RefMul
{
public:
    RefMul(int& a, int& b) : a(a), b(b) {}

    operator int() const { return a * b; }

private:
    int& a;
    int& b;
};

struct creature {
    int numberofhands;
    int fingersperhand;
    RefMul totalfingers{numberofhands, fingersperhand};
};

Demo

注意:要将RefMulprintf一起使用,您必须转为int

printf("%d", int(human.totalfingers));

如果使用c ++方式打印,则不需要该演员表:

std::cout << human.totalfingers;

答案 3 :(得分:1)

如果您在一致性之后,可以反过来进行更改。用常量方法替换两个成员变量,这些方法只返回成员变量的副本。这样,您访问数据的方式是一致的,并且您不必担心某些代码在不应该更改成员变量的值时。

答案 4 :(得分:0)

其他人提供了非常好的答案。如果您正在寻找一致性,可能最简单的方法是使用成员函数(正如@Jesper Juhl已经回答的那样)。

另一方面,如果您严格要使用从其他成员自动计算的类成员,则可以使用属性。属性(如在C#和Groovy中定义的)不是C ++的标准特性,但有一些方法可以用C ++实现它们。 This SO question非常清楚地概述了在C ++中定义和使用属性的方法。我最喜欢的定义属性的方法是利用Microsoft特定的Visual C ++属性扩展(显然,这种方法特定于Microsoft Visual C ++)。可以在MSDN中找到Visual C ++中的属性文档。使用Visual C ++中的属性,您的代码可以修改为:

struct creature {
    int numberofhands; // use of public member variables are generally discouraged
    int fingersperhand;

    __declspec(property(get = get_totalfingers)) // Microsoft-specific
    int totalfingers;

private:
    int fingers;
    int get_totalfingers() 
    {
        return numberofhands * fingersperhand; // This is where the automatic calculation takes place. 
    }
}; 

这个类可以像这样使用:

#include <iostream>
int main()
{
    creature martian;
    martian.numberofhands = 2;
    martian.fingersperhand = 4; // Marvin the Martian had 4!

    // This line will print 8
    std::cout << "Total fingers: " << martian.totalfingers << std::endl;

    return 0;
}

正如我之前所说,属性不是C ++的标准功能,但是有很多方法可以在C ++中使用它们,这些方法要么依赖于智能技巧,要么使用特定于编译器的功能。恕我直言,使用简单的功能(如@Jesper Juhl所描述的)是一个更好的选择。