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