C++ 有没有办法为同一个参数使用不同的类型来初始化 class?
C++ Is there a way to initialize a class using different types for the same argument?
我有一个带有零个或两个参数的 class Obj。
- 没有参数
- 第一个参数始终是 std::string 名称。
- 第二个参数应该是三种不同的 class 类型。
我想要这样的东西:
class Sphere{
public:
int radius=1;
int a;
};
class Plane{
public:
int a=11;
int b=12;
int c=13;
};
class Light{
public:
int pos=555;
int a;
};
class Obj{
public:
std::string name;
Sphere s;
Light l;
Plane p;
int type;
bool defined;
//with no arguments
Obj(){
defined=false;
type=0;
}
//Type Sphere as second arg
Obj(std::string name,Sphere _s){
defined=true;
type=1;
s=_s;
}
//Or Type Light as second arg
Obj(std::string name,Light _l){
defined=true;
type=2;
l=_l;
}
//Or Type Plane as second arg
Obj(std::string name,Plane _p){
defined=true;
type=3;
p=_p;
}
};
意思应该是能够将多个不同类型的对象放在同一个数组中,仅以一种方式键入。
有可能吗?任何建议将不胜感激。谢谢
编辑:
(C++11)
知道它可以编译已经是一个很好的开始。谢谢。
The above example only works if the Sphere, Plane, Light classes have
no arguments.
将相同的参数编号添加到 Sphere、Plane、Light classes 也失败了。如果 3 classes 具有不同数量的参数,则相同。
#include <iostream>
class Sphere{
public:
int radius=1;
int a;
Sphere( int _a ){
a=_a;
}
};
class Plane{
public:
int a=11;
int b=12;
int c=13;
Plane( int _a ){
a=_a;
}
//Plane(int _a,int _b,int _c){
// a=_a;b=_b;c=_c;
//}
};
class Light{
public:
int pos=555;
int a;
Light(int _a){
a=_a;
}
};
class Obj{
public:
std::string name;
Sphere s;
Light l;
Plane p;
int type;
bool defined;
//with no arguments
Obj(){
defined=false;
type=0;
}
//Type Sphere as second arg
Obj(std::string _name,Sphere _s){
name=_name;
defined=true;
type=1;
s=_s;
}
//Or Type Light as second arg
Obj(std::string _name,Light _l){
name=_name;
defined=true;
type=2;
l=_l;
}
//Or Type Plane as second arg
Obj(std::string _name,Plane _p){
name = _name;
defined=true;
type=3;
p=_p;
}
};
using namespace std;
int main()
{
int a=111;
int b=222;
int c=333;
Obj sph1=Obj("sphere1",Sphere(a));
Obj sph2=Obj("sphere2",Sphere(b));
Obj lig1=Obj("Light1", Light(c));
Obj lig2=Obj("Light2", Light(c));
//Obj pla1=Obj("Plane1", Plane(a,b,c));
//Obj pla2=Obj("Plane2", Plane(c,b,a));
cout<<"sp1 name:" << sph1.name << endl;
cout<<"sp1 radius:"<< sph1.s.radius << endl;
//cout<<"pla1 name:" << pla1.name << endl;
//cout<<"pla1 p1:" << pla1.p.p1 << endl;
//cout<<"pla2 name:" << pla1.name << endl;
//cout<<"pla2 p1:" << pla1.p.p1 << endl;
cout<<"Hello"<<endl;
return 0;
}
此处编译错误:
Error:
vt.cpp: In constructor ‘Obj::Obj()’:
vt.cpp:64:10: error: no matching function for call to ‘Sphere::Sphere()’
Obj(){
^
vt.cpp:22:5: note: candidate: Sphere::Sphere(int)
Sphere( int _a ){
^~~~~~
vt.cpp:22:5: note: candidate expects 1 argument, 0 provided
vt.cpp:18:7: note: candidate: constexpr Sphere::Sphere(const Sphere&)
class Sphere{
^~~~~~
此 C++17 解决方案是 std::variant
,尽管基于 defined
,您可能希望将其包装在 std::optional
.
中
class Obj{
public:
std::string name;
using Value = std::variant<Sphere, Light, Plane>;
std::optional<Value> v;
//with no arguments
Obj() = default;
//Type Sphere as second arg
Obj(std::string name,Sphere _s) : v{std::make_optional<Value>(_s)} { }
// ...
};
std::variant
会跟踪为您存储了哪种类型,您不必为所有三个实例的开销付费。 std::optional
为您处理 defined
部分。
通过模板化构造函数并盲目地传递第二个参数,您可能会更巧妙一些。
template <typename T>
Obj(std::string name, T _v) : v{std::make_optional<Value>(_v)} { }
我有一个带有零个或两个参数的 class Obj。
- 没有参数
- 第一个参数始终是 std::string 名称。
- 第二个参数应该是三种不同的 class 类型。
我想要这样的东西:
class Sphere{
public:
int radius=1;
int a;
};
class Plane{
public:
int a=11;
int b=12;
int c=13;
};
class Light{
public:
int pos=555;
int a;
};
class Obj{
public:
std::string name;
Sphere s;
Light l;
Plane p;
int type;
bool defined;
//with no arguments
Obj(){
defined=false;
type=0;
}
//Type Sphere as second arg
Obj(std::string name,Sphere _s){
defined=true;
type=1;
s=_s;
}
//Or Type Light as second arg
Obj(std::string name,Light _l){
defined=true;
type=2;
l=_l;
}
//Or Type Plane as second arg
Obj(std::string name,Plane _p){
defined=true;
type=3;
p=_p;
}
};
意思应该是能够将多个不同类型的对象放在同一个数组中,仅以一种方式键入。
有可能吗?任何建议将不胜感激。谢谢
编辑:
(C++11)
知道它可以编译已经是一个很好的开始。谢谢。
The above example only works if the Sphere, Plane, Light classes have no arguments.
将相同的参数编号添加到 Sphere、Plane、Light classes 也失败了。如果 3 classes 具有不同数量的参数,则相同。
#include <iostream>
class Sphere{
public:
int radius=1;
int a;
Sphere( int _a ){
a=_a;
}
};
class Plane{
public:
int a=11;
int b=12;
int c=13;
Plane( int _a ){
a=_a;
}
//Plane(int _a,int _b,int _c){
// a=_a;b=_b;c=_c;
//}
};
class Light{
public:
int pos=555;
int a;
Light(int _a){
a=_a;
}
};
class Obj{
public:
std::string name;
Sphere s;
Light l;
Plane p;
int type;
bool defined;
//with no arguments
Obj(){
defined=false;
type=0;
}
//Type Sphere as second arg
Obj(std::string _name,Sphere _s){
name=_name;
defined=true;
type=1;
s=_s;
}
//Or Type Light as second arg
Obj(std::string _name,Light _l){
name=_name;
defined=true;
type=2;
l=_l;
}
//Or Type Plane as second arg
Obj(std::string _name,Plane _p){
name = _name;
defined=true;
type=3;
p=_p;
}
};
using namespace std;
int main()
{
int a=111;
int b=222;
int c=333;
Obj sph1=Obj("sphere1",Sphere(a));
Obj sph2=Obj("sphere2",Sphere(b));
Obj lig1=Obj("Light1", Light(c));
Obj lig2=Obj("Light2", Light(c));
//Obj pla1=Obj("Plane1", Plane(a,b,c));
//Obj pla2=Obj("Plane2", Plane(c,b,a));
cout<<"sp1 name:" << sph1.name << endl;
cout<<"sp1 radius:"<< sph1.s.radius << endl;
//cout<<"pla1 name:" << pla1.name << endl;
//cout<<"pla1 p1:" << pla1.p.p1 << endl;
//cout<<"pla2 name:" << pla1.name << endl;
//cout<<"pla2 p1:" << pla1.p.p1 << endl;
cout<<"Hello"<<endl;
return 0;
}
此处编译错误:
Error:
vt.cpp: In constructor ‘Obj::Obj()’:
vt.cpp:64:10: error: no matching function for call to ‘Sphere::Sphere()’
Obj(){
^
vt.cpp:22:5: note: candidate: Sphere::Sphere(int)
Sphere( int _a ){
^~~~~~
vt.cpp:22:5: note: candidate expects 1 argument, 0 provided
vt.cpp:18:7: note: candidate: constexpr Sphere::Sphere(const Sphere&)
class Sphere{
^~~~~~
此 C++17 解决方案是 std::variant
,尽管基于 defined
,您可能希望将其包装在 std::optional
.
class Obj{
public:
std::string name;
using Value = std::variant<Sphere, Light, Plane>;
std::optional<Value> v;
//with no arguments
Obj() = default;
//Type Sphere as second arg
Obj(std::string name,Sphere _s) : v{std::make_optional<Value>(_s)} { }
// ...
};
std::variant
会跟踪为您存储了哪种类型,您不必为所有三个实例的开销付费。 std::optional
为您处理 defined
部分。
通过模板化构造函数并盲目地传递第二个参数,您可能会更巧妙一些。
template <typename T>
Obj(std::string name, T _v) : v{std::make_optional<Value>(_v)} { }