C++ C++;在if-else内部声明派生类对象,并在外部使用它

C++ C++;在if-else内部声明派生类对象,并在外部使用它,c++,inheritance,C++,Inheritance,我有一个名为Alma的(父)类,带有(虚拟)函数Getwidth(),还有两个Alma的派生类,名为Birs(带有特殊函数Getheight())和Citrom(带有特殊函数Getdepth())。我想声明一个名为Attila的对象,它的类型是Birs或Citrom,具体取决于bool。稍后,我想使用公共函数Getwidth()和特殊函数(取决于前面提到的bool) 我的(不工作)代码: /**/ /*班级*/ 母校{ public:virtual int Getwidth()=0; /*等等*

我有一个名为
Alma
的(父)类,带有(虚拟)函数
Getwidth()
,还有两个
Alma
的派生类,名为
Birs
(带有特殊函数
Getheight()
)和
Citrom
(带有特殊函数
Getdepth()
)。我想声明一个名为
Attila
的对象,它的类型是
Birs
Citrom
,具体取决于
bool
。稍后,我想使用公共函数
Getwidth()
和特殊函数(取决于前面提到的
bool

我的(不工作)代码:

/**/
/*班级*/
母校{
public:virtual int Getwidth()=0;
/*等等*/
}
Birs类:公共Alma{
int Getwidth(){return 1;}
public:int Getheight(){return 2;}
/*等等*/
}
Citrom类:公共Alma{
int Getwidth(){return 3;}
public:int Getdepth(){return 4;}
/*等等*/
}
/*...*/
/*使用它们*/
void Useobjects(){
/*根据bool创建对象*/
if(b00lvar){
Birs和或();

Std::CUT> P>不能定义一个对象,它的类型是这个或那个,取决于其他东西。C++是一个静态类型的语言。C++意味着每个对象的类型都是在编译时确定的。其他语言,如Perl或JavaScript,是动态类型的,其中对象的类型是在运行时,单个对象可以是一件事,在一个点上,也可以是另一件事,在另一个点上

<>但是C++没有这样工作。< /P> 要执行类似于您正在尝试执行的操作,您必须重构代码,并使用虚拟超类。类似于以下内容:

void UseObject(Alma &andor)
{
  /*Using the common part of object*/  
  std::cout<<andor.Getwidth()<<std::endl;

  /*Using the special part of object*/

  /* This part is your homework assignment */
}


void Useobjects(){

/*Create object depending on bool*/
  if(b00lvar){
    Birs andor;
    std::cout<<Andor.Getwidth()<<" "<<Andor.Getheight()<<std::endl;
    UseObject(andor);
  }else{
    Citrom andor;
    std::cout<<Andor.Getwidth()<<" "<<Andor.Getdepth()<<std::endl;
    UseObject(andor);
  }
}
void UseObject(Alma和或)
{
/*使用对象的公共部分*/

std::cout这是多态对象处理的经典案例。请确保您熟悉该概念以及指针和引用

您需要的是如下所示:

Alma* Andor;

 if(b00lvar){
    Andor = new Birs();
    std::cout<<Andor->Getwidth()<<" "<<Andor->Getheight()<<std::endl;
  }else{
    Andor = new Citrom();  
    std::cout<<Andor->Getwidth()<<" "<<Andor->Getdepth()<<std::endl;
  }
Alma*和或;
if(b00lvar){
和或=新的BIR();

std::cout您可以使用指针语义和使用
dynamic\u cast
的类型内省来实现这一点。我扩展了您的示例,以展示如何实现它

这是你的电话号码

两件事:

  • 如果要在
    If
    之外使用它,则必须在
    If
    之外声明它
  • 这种多态性需要引用或指针
  • unique_ptr和或;
    if(b00lvar){
    和或=使_独特();
    }否则{
    和或=使_独特();
    }
    std::cout Getwidth()如果对象的类型(Alma或Citrom)是在启动时确定的,那么它是一个典型的多态性,如其他答案所述:
    

    您的设计中缺少的是,用共同的行为命名共同的祖先(例如Gyumolcs)


    如果对象一次充当Alma,另一次充当Citrom,则应实现一个类,该类具有标志或枚举(act_as_Citrom,act_as_Alma),或者,如果行为仅限于一个方法,则该对象应具有一个参数,该参数指示要执行的操作(Alma-like或Citrom-like)如果一个对象是已知的B或C,那么多态性并不总是一个好办法。在这种情况下,
    boost::variant
    通常更简洁

    话虽如此,如果你想沿着多态路线走下去,记住一些指导设计的东西是很重要的

    多态性意味着运行时多态性。也就是说,程序无法知道对象的真实类型。它也无法知道对象可能是什么类型的完整集合,因为另一个开发人员可能会制造一种模块代码一无所知的类型。此外,当使用Alma接口时,代码不需要知道任何东西ng更多。调用诸如“我知道这将是一个
    Citrom
    ,因为bool是真的”这样的魔术,为接下来几周或几个月的代码维护噩梦打下了基础。在商业、生产代码中完成时,会导致昂贵而尴尬的错误查找。不要这样做

    这表明
    Alma
    类型的任何对象的所有相关信息必须在
    Alma
    界面中可用

    在我们的案例中,相关信息是它是否具有高度和/或深度的概念

    在这种情况下,我们可能应该在基本接口中包含这些属性,并提供函数,以便程序可以在使用该属性之前查询该属性是否有效

    下面是一些类似于您的示例的内容:

    #include <iostream>
    #include <memory>
    #include <typeinfo>
    #include <string>
    #include <exception>
    #include <stdexcept>
    
    
    // separating out these optional properties will help me to reduce clutter in Alma
    
    struct HeightProperty
    {
        bool hasHeight() const { return impl_hasHeight(); }
        int getHeight() const { return impl_getHeight(); }
    
    private:
    
        // provide default implementations
        virtual bool impl_hasHeight() const { return false; }
        virtual int impl_getHeight() const { throw std::logic_error("getHeight not implemented for this object"); }
    
    };
    
    struct DepthProperty
    {
        bool hasDepth() const { return impl_hasDepth(); }
        int getDepth() const { return impl_getDepth(); }
    
    private:
    
        virtual bool impl_hasDepth() const { return false; }
        virtual int impl_getDepth() const { throw std::logic_error("getDepth not implemented for this object"); }
    
    };
    
    class Alma : public HeightProperty, public DepthProperty
    {
    public:
        Alma() = default;
        virtual ~Alma() = default;
    
        // note: nonvirtual interface defers to private virtual implementation
        // this is industry best practice
        int getWidth() const { return impl_getWidth(); }
        const std::string& type() const {
            return impl_getType();
        }
    private:
        virtual int impl_getWidth() const = 0;
        virtual const std::string& impl_getType() const = 0;
    
    };
    
    class Birs: public Alma
    {
    private:
        // implement the mandatory interface
        int impl_getWidth() const override { return 1; }
        const std::string& impl_getType() const override {
            static const std::string type("Birs");
            return type;
        }
    
        // implement the HeightProperty optional interface
        bool impl_hasHeight() const override { return true; }
        int impl_getHeight() const override { return 2; }
    };
    
    class Citrom: public Alma
    {
    private:
        // implement the mandatory interface
        int impl_getWidth() const override { return 3; }
        const std::string& impl_getType() const override {
            static const std::string type("Citrom");
            return type;
        }
    
        // implement the DepthProperty optional interface
    
        bool impl_hasDepth() const override { return true; }
        int impl_getDepth() const override { return 4; }
    };
    
    /*...*/
    /*Using them*/
    
    // generate either a Birs or a Citrom, but return the Alma interface
    std::unique_ptr<Alma> make_alma(bool borc)
    {
        if (borc) {
            return std::make_unique<Birs>();
        }
        else {
            return std::make_unique<Citrom>();
        }
    }
    
    void Useobjects()
    {
        for (bool b : { true, false })
        {
            std::unique_ptr<Alma> pa = make_alma(b);
    
            std::cout << "this object's typeid name is " << pa->type() << std::endl;
            std::cout << "it's width is : " << pa->getWidth() << std::endl;
    
            if(pa->hasHeight()) {
                std::cout << "it's height is: " << pa->getHeight() << std::endl;
            }
            if(pa->hasDepth()) {
                std::cout << "it's depth is: " << pa->getDepth() << std::endl;
            }
        }
    }
    
    int main()
    {
        Useobjects();
        return 0;
    }
    

    @Richard Hodges这是学校级别的作业,而不是生产代码。在不知道基本指针是什么感觉的情况下,不应该深入研究智能指针。我理解并欣赏你的推理。但是,我认为我们无法对提出问题的OP的动机做出假设。因此,作为一名教育r因此,这些答案可能会被成千上万的人阅读。因为我们最终很可能会与受其中一个影响的人一起工作,我认为我们有义务教会人们正确的事情(tm),不是吗?
    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Alma{
    public:
        virtual int Getwidth() = 0;
    };
    
    class Birs: public Alma{
    public:
        int Getwidth()  { return 1; }
        int Getheight() { return 2; }
    };
    
    class Citrom: public Alma{
    public:
        int Getwidth() { return 3; }
        int Getdepth() { return 4; }
    };
    
    shared_ptr<Alma> make_attila(bool birs)
    {
        if (birs)
            return make_shared<Birs>();
        else
            return make_shared<Citrom>();
    }
    
    void test_attila(shared_ptr<Alma> attila)
    {
        cout << "width: " << attila->Getwidth() << "\n";
        if (auto as_birs = dynamic_pointer_cast<Birs>(attila))
            cout << "height: " << as_birs->Getheight() << "\n";
        else if (auto as_citrom = dynamic_pointer_cast<Citrom>(attila))
            cout << "depth: " << as_citrom->Getdepth() << "\n";
    }
    
    int main() {
        shared_ptr<Alma> attila = make_attila(true);
        test_attila(attila);
        attila = make_attila(false);
        test_attila(attila);
        return 0;
    }
    
    template <class Derived>
    shared_ptr<Alma> make_attila()
    {
       return make_shared<Derived>();
    }
    
    unique_ptr<Alma> Andor;
    
    if (b00lvar) {
      Andor = make_unique<Birs>();
    } else {
      Andor = make_unique<Citrom>();
    }
    
    std::cout << Andor->Getwidth() << std::endl;
    
    #include <iostream>
    #include <memory>
    #include <typeinfo>
    #include <string>
    #include <exception>
    #include <stdexcept>
    
    
    // separating out these optional properties will help me to reduce clutter in Alma
    
    struct HeightProperty
    {
        bool hasHeight() const { return impl_hasHeight(); }
        int getHeight() const { return impl_getHeight(); }
    
    private:
    
        // provide default implementations
        virtual bool impl_hasHeight() const { return false; }
        virtual int impl_getHeight() const { throw std::logic_error("getHeight not implemented for this object"); }
    
    };
    
    struct DepthProperty
    {
        bool hasDepth() const { return impl_hasDepth(); }
        int getDepth() const { return impl_getDepth(); }
    
    private:
    
        virtual bool impl_hasDepth() const { return false; }
        virtual int impl_getDepth() const { throw std::logic_error("getDepth not implemented for this object"); }
    
    };
    
    class Alma : public HeightProperty, public DepthProperty
    {
    public:
        Alma() = default;
        virtual ~Alma() = default;
    
        // note: nonvirtual interface defers to private virtual implementation
        // this is industry best practice
        int getWidth() const { return impl_getWidth(); }
        const std::string& type() const {
            return impl_getType();
        }
    private:
        virtual int impl_getWidth() const = 0;
        virtual const std::string& impl_getType() const = 0;
    
    };
    
    class Birs: public Alma
    {
    private:
        // implement the mandatory interface
        int impl_getWidth() const override { return 1; }
        const std::string& impl_getType() const override {
            static const std::string type("Birs");
            return type;
        }
    
        // implement the HeightProperty optional interface
        bool impl_hasHeight() const override { return true; }
        int impl_getHeight() const override { return 2; }
    };
    
    class Citrom: public Alma
    {
    private:
        // implement the mandatory interface
        int impl_getWidth() const override { return 3; }
        const std::string& impl_getType() const override {
            static const std::string type("Citrom");
            return type;
        }
    
        // implement the DepthProperty optional interface
    
        bool impl_hasDepth() const override { return true; }
        int impl_getDepth() const override { return 4; }
    };
    
    /*...*/
    /*Using them*/
    
    // generate either a Birs or a Citrom, but return the Alma interface
    std::unique_ptr<Alma> make_alma(bool borc)
    {
        if (borc) {
            return std::make_unique<Birs>();
        }
        else {
            return std::make_unique<Citrom>();
        }
    }
    
    void Useobjects()
    {
        for (bool b : { true, false })
        {
            std::unique_ptr<Alma> pa = make_alma(b);
    
            std::cout << "this object's typeid name is " << pa->type() << std::endl;
            std::cout << "it's width is : " << pa->getWidth() << std::endl;
    
            if(pa->hasHeight()) {
                std::cout << "it's height is: " << pa->getHeight() << std::endl;
            }
            if(pa->hasDepth()) {
                std::cout << "it's depth is: " << pa->getDepth() << std::endl;
            }
        }
    }
    
    int main()
    {
        Useobjects();
        return 0;
    }
    
    this object's typeid name is Birs
    it's width is : 1
    it's height is: 2
    this object's typeid name is Citrom
    it's width is : 3
    it's depth is: 4