如何在 C++ 中编写具有多个数据字段的类 Java 枚举类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1965249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to write a Java-enum-like class with multiple data fields in C++?
提问by missingfaktor
Coming from a Java background, I find C++'s enums very lame. 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++.
来自 Java 背景,我发现 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!
谢谢!
回答by Anton
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();
回答by bcmpinc
With C++11's introduction of constexpr. There's yet another way to implement typed enums. One that works practically the same as normal enums (is stored as an intvariable and can be used in a switchstatement), but also allows them to have member functions.
随着 C++11 对constexpr. 还有另一种实现类型化枚举的方法。一种与普通枚举几乎相同的工作方式(存储为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,但是在类内部,类还不是完整的类型,因此无法实例化。
回答by Omnifarious
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;
}
回答by UltraInstinct
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..
这只是一个小代码,我相信您可以修改它以满足您的需要..

