简体   繁体   English

如何在 C++ 中编写具有多个数据字段的类 Java 枚举类?

[英]How to write a Java-enum-like class with multiple data fields in C++?

Coming from a Java background, I find C++'s enums very lame.来自 Java 背景,我发现 C++ 的枚举非常蹩脚。 I wanted to know how to write Java-like enums (the ones in which the enum values are objects, and can have attributes and methods) in C++.我想知道如何在 C++ 中编写类似 Java 的枚举(枚举值是对象,并且可以具有属性和方法)。

For example, translate the following Java code (a part of it, sufficient to demonstrate the technique) to C++ :例如,将以下 Java 代码(其中的一部分,足以演示该技术)转换为 C++:

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass()   { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage:  java Planet <earth_weight>");
            System.exit(-1);
        }
        double earthWeight = Double.parseDouble(args[0]);
        double mass = earthWeight/EARTH.surfaceGravity();
        for (Planet p : Planet.values())
           System.out.printf("Your weight on %s is %f%n",
                             p, p.surfaceWeight(mass));
    }
}

Any help would be greatly appreciated!任何帮助将不胜感激!

Thanks!谢谢!

One way to simulate Java enums is to create a class with a private constructor that instantiates copies of itself as static variables:模拟 Java 枚举的一种方法是创建一个具有私有构造函数的类,该构造函数将自身的副本实例化为静态变量:

class Planet {  
  public: 
    // Enum value DECLARATIONS - they are defined later 
    static const Planet MERCURY;  
    static const Planet VENUS;  
    // ... 

  private: 
    double mass;   // in kilograms  
    double radius; // in meters  

  private: 
    Planet(double mass, double radius) {  
        this->mass = mass;  
        this->radius = radius;  
    } 

  public: 
    // Properties and methods go here 
}; 

// Enum value DEFINITIONS 
// The initialization occurs in the scope of the class,  
// so the private Planet constructor can be used. 
const Planet Planet::MERCURY = Planet(3.303e+23, 2.4397e6);  
const Planet Planet::VENUS = Planet(4.869e+24, 6.0518e6);  
// ... 

Then you can use the enums like this:然后你可以像这样使用枚举:

double gravityOnMercury = Planet::MERCURY.SurfaceGravity();

With C++11's introduction of constexpr .随着 C++11 引入constexpr There's yet another way to implement typed enums.还有另一种实现类型化枚举的方法。 One that works practically the same as normal enums (is stored as an int variable and can be used in a switch statement), but also allows them to have member functions.一种与普通枚举几乎相同的工作方式(存储为int变量并可在switch语句中使用),但也允许它们具有成员函数。

In the header file you would put:在头文件中,您将放置:

class Planet {
    int index;
public:
    static constexpr int length() {return 8;}
    Planet() : index(0) {}
    constexpr explicit Planet(int index) : index(index) {}
    constexpr operator int() const { return index; }

    double mass() const;
    double radius() const;

    double surfaceGravity() const;
};
constexpr Planet PLANET_MERCURY(0);
constexpr Planet PLANET_VENUS(1);
constexpr Planet PLANET_EARTH(2);
// etc.

And in the source file:在源文件中:

static double G = 6.67300E-11;

double Planet::mass() {
    switch(index) {
        case PLANET_MERCURY: return 3.303e+23;
        case PLANET_VENUS: return 4.869e+24;
        case PLANET_EARTH: return 5.976e+24;
        // Etc.
    }
}

double Planet::radius() {
    // Similar to mass.
}

double Planet::surfaceGravity() {
    return G * mass() / (radius() * radius());
}

Which can then be used as:然后可以用作:

double gravityOnMercury = PLANET_MERCURY.SurfaceGravity();

Unfortunately, the enum entries cannot be defined as static constants within the class body.不幸的是,枚举条目不能定义为类体内的静态常量。 They must be initialized upon declaration, because they are constexpr , but inside the class, the class is not yet a complete type and thus cannot be instantiated.它们必须在声明时初始化,因为它们是constexpr ,但在类内部,该类还不是完整的类型,因此无法实例化。

This is ugly, verbose, and generally a dumb way to go.这是丑陋的,冗长的,而且通常是一种愚蠢的方法。 But I figured I'd post a complete code example by way of explanation.但我想我会通过解释的方式发布一个完整的代码示例。 For extra points it's actually possible to define a compile-time expanded iteration over the solar planets by tweaking the template specializations just a tad.对于额外的点,实际上可以通过稍微调整模板特化来定义对太阳行星的编译时扩展迭代。

#include <string>
#include <sstream>
#include <iostream>
#include <cstdlib>

class Planet {
 public:
   static const double G = 6.67300E-11;

   Planet(const ::std::string &name, double mass, double radius)
        : name_(name), mass_(mass), radius_(radius)
      {}
   const ::std::string &name() const { return name_; }
   double surfaceGravity() const {
      return G * mass_ / (radius_ * radius_);
   }
   double surfaceWeight(double otherMass) const {
      return otherMass * surfaceGravity();
   }

 private:
   const ::std::string name_;
   const double mass_;
   const double radius_;
};

enum SolarPlanets {
   MERCURY,
   VENUS,
   EARTH,
   MARS,
   JUPITER,
   SATURN,
   URANUS,
   NEPTUNE
};

template <SolarPlanets planet>
class SolarPlanet : public Planet {
};

template <>
class SolarPlanet<MERCURY> : public Planet {
 public:
   SolarPlanet() : Planet("MERCURY", 3.303e+23, 2.4397e6) {}
};

template <>
class SolarPlanet<VENUS> : public Planet {
 public:
   SolarPlanet() : Planet("VENUS", 4.869e+24, 6.0518e6) {}
};

template <>
class SolarPlanet<EARTH> : public Planet {
 public:
   SolarPlanet() : Planet("EARTH", 5.976e+24, 6.37814e6) {}
};

template <>
class SolarPlanet<MARS> : public Planet {
 public:
   SolarPlanet() : Planet("MARS", 6.421e+23, 3.3972e6) {}
};

template <>
class SolarPlanet<JUPITER> : public Planet {
 public:
   SolarPlanet() : Planet("JUPITER", 1.9e+27, 7.1492e7 ) {}
};

template <>
class SolarPlanet<SATURN> : public Planet {
 public:
   SolarPlanet() : Planet("SATURN", 5.688e+26, 6.0268e7) {}
};

template <>
class SolarPlanet<URANUS> : public Planet {
 public:
   SolarPlanet() : Planet("URANUS", 8.686e+25, 2.5559e7) {}
};

template <>
class SolarPlanet<NEPTUNE> : public Planet {
 public:
   SolarPlanet() : Planet("NEPTUNE", 1.024e+26, 2.4746e7) {}
};

void printTerranWeightOnPlanet(
   ::std::ostream &os, double terran_mass, const Planet &p
   )
{
   const double mass = terran_mass / SolarPlanet<EARTH>().surfaceGravity();
   os << "Your weight on " << p.name() << " is " << p.surfaceWeight(mass) << '\n';
}

int main(int argc, const char *argv[])
{
   if (argc != 2) {
      ::std::cerr << "Usage: " << argv[0] << " <earth_weight>\n";
      return 1;
   }
   const double earthweight = ::std::atof(argv[1]);
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<MERCURY>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<VENUS>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<EARTH>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<MARS>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<JUPITER>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<SATURN>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<URANUS>());
   printTerranWeightOnPlanet(::std::cout, earthweight, SolarPlanet<NEPTUNE>());
   return 0;
}

May be this is what you want --可能这就是你想要的——

#include<iostream>

using namespace std;

class Planet {
    double mass,radius;

    Planet(double m, double r) : mass(m) : radius(r) {}

public:
    static const Planet MERCURY;

    void show(){
        cout<<mass<<","<<radius<<endl;
    }
} ;
const Planet Planet::MERCURY = Planet(1.0,1.2);

int main(){
    Planet p = Planet::MERCURY;
    p.show();
}

This is just a small code, Im sure you can modify this to suit your needs..这只是一个小代码,我相信你可以修改它以满足你的需要..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM