来自Java背景,我发现C ++的枚举非常蹩脚。我想知道如何在C ++中编写类似Java的枚举(枚举值是对象,可以有属性和方法)。
例如,将以下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));
}
}
非常感谢任何帮助!
谢谢!
答案 0 :(得分:69)
模拟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);
// ...
然后你可以使用这样的枚举:
double gravityOnMercury = Planet::MERCURY.SurfaceGravity();
答案 1 :(得分:6)
使用C ++ 11引入constexpr
。还有另一种实现类型枚举的方法。一个与普通枚举实际上相同的(存储为int
变量,可以在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
,但在类中,类不是完整类型,因此无法实例化。
答案 2 :(得分:1)
这是丑陋的,冗长的,通常是一种愚蠢的方式。但我想我会通过解释发布一个完整的代码示例。对于额外的点,实际上可以通过稍微调整模板特化来定义太阳行星上的编译时扩展迭代。
#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;
}
答案 3 :(得分:1)
可能这就是你想要的 -
#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();
}
这只是一个小代码,我相信你可以修改它以满足你的需求..