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

问题描述

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

  • 没有争论
  • 一个参数总是一个 std::string 名称
  • 第二个参数应该是三种不同的类类型。

我想要这样的:

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)

知道它可以编译已经是一个很好的开始。谢谢。

以上示例仅在 Sphere、Plane、Light 类具有 没有争论。

向 Sphere、Plane、Light 类添加相同的参数编号也会失败。如果 3 个类具有不同数量的参数,则相同。

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...