如何用C ++中的多个数据字段编写一个类似Java的枚举类?
来自Java的背景,我发现C ++的枚举非常蹩脚。 我想知道如何在C ++中编写类似Java的枚举(enum值是对象,可以有属性和方法)。
例如,将以下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)); } }
任何帮助将不胜感激!
谢谢!
一种模拟Java枚举的方法是创build一个具有私有构造函数的类,将其自身的副本实例化为静态variables:
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); // ...
那么你可以使用像这样的枚举:
double gravityOnMercury = Planet::MERCURY.SurfaceGravity();
用C ++ 11引入了constexpr
。 还有另一种方法来实现types枚举。 一个与普通枚举几乎相同的工作(存储为一个int
variables,可以在switch
语句中使用),但也允许他们具有成员函数。
在头文件中,你会放:
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.
并在源文件中:
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()); }
然后可以用作:
double gravityOnMercury = PLANET_MERCURY.SurfaceGravity();
不幸的是,枚举条目不能被定义为类体内的静态常量。 它们必须在声明时初始化,因为它们是constexpr
,但是在类内部,类还不是一个完整的types,因此不能被实例化。
可能是这个你想要的 –
#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(); }
这只是一个小代码,我确定你可以修改这个来适应你的需要..
这是丑陋的,冗长的,通常是愚蠢的方式去。 但我想通过解释的方式发布一个完整的代码示例。 对于额外的点,实际上可以通过调整模板专门化来定义在太阳行星上的编译时间扩展迭代。
#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; }