C++ 有没有办法为同一个参数使用不同的类型来初始化 class?

C++ Is there a way to initialize a class using different types for the same argument?

我有一个带有零个或两个参数的 class Obj。

我想要这样的东西:

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)} { }