我有一个名为public void start(Stage primaryStage) {
String[] text = {"3", "2", "1"};
Text[] textNodes = new Text[text.length];
for (int i = 0; i < text.length; i++) {
Text t = new Text(text[i]);
t.setTranslateX(20 + i * 50);
t.setTranslateY(100);
textNodes[i] = t;
}
SwapAnimationQueue swapper = new SwapAnimationQueue(textNodes);
Pane p = new Pane();
p.getChildren().addAll(textNodes);
swapper.swap(0, 1);
swapper.swap(1, 2);
swapper.swap(0, 1);
Scene scene = new Scene(p, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
swapper.play();
}
的(父)类,其中包含(虚拟)函数Alma
和两个派生类Getwidth()
,名为Alma
(具有特殊函数{ {1}})和Birs
(使用特殊功能Getheight()
)。我想声明一个名为Citrom
的对象 - 哪个类型为Getdepth()
或Attila
,具体取决于Birs
。稍后,我想使用公共函数Citrom
以及特殊函数(取决于提到的bool
)。
我的(不工作)代码:
Getwidth()
答案 0 :(得分:1)
这是多态对象处理的经典案例。只需确保您熟悉该概念以及指针和参考。
您需要的是:
dynamic_cast
接下来使用{{1}}返回派生类型,最后当然不要忘记删除对象。但首先要阅读这些概念。
答案 1 :(得分:0)
您无法定义类型为this或that的单个对象,具体取决于其他内容。 C ++不能这样工作。 C ++是一种静态类型的语言。这意味着每个对象的类型都是在编译时确定的。其他语言,如Perl或Javascript,是动态类型的,其中对象的类型是在运行时确定的,单个对象在一个点上可以是一样,在不同点上可以是其他东西。
但是C ++不能这样工作。
要执行类似于您尝试执行的操作,您必须重构代码,并使用虚拟超类。像这样:
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);
}
}
另一种方法是使用两个指针,在这种情况下,将两个指针传递给UseObject()
。其中一个指针始终为nullptr
,另一个指向实例化对象的指针,UseObject()
编码以处理传入的任何对象。
这也是可能的,但会导致丑陋的代码,如果我是一名教授C ++的讲师,我会记下那些提交代码的人。
答案 2 :(得分:0)
您可以使用指针语义和dynamic_cast
类型内省来执行此操作。我扩展了你的例子来展示我将如何接近它。
以下是Demo
#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;
}
下一步是使make_attila
成为模板函数,将Derived类作为模板参数而不是bool。
template <class Derived>
shared_ptr<Alma> make_attila()
{
return make_shared<Derived>();
}
答案 3 :(得分:0)
两件事:
if
之外使用它, 必须在if
之外宣布它。unique_ptr<Alma> Andor;
if (b00lvar) {
Andor = make_unique<Birs>();
} else {
Andor = make_unique<Citrom>();
}
std::cout << Andor->Getwidth() << std::endl;
其他一些答案建议使用shared_ptr
,但这样做太过分了。 99%的时间unique_ptr
就足够了。
答案 4 :(得分:0)
如果在启动时决定了对象的类型(Alma或Citrom),那么它就是一个经典的多态,正如其他答案所描述的那样: https://stackoverflow.com/a/36218884/185881
您在设计中缺少的是命名具有共同行为的共同祖先(例如Gyumolcs)。
如果对象曾经作为Alma而其他时候作为Citrom,你应该实现一个类,它有一个标志或枚举(ACT_AS_CITROM,ACT_AS_ALMA),或者,如果行为仅限于一个方法,那么它应该有一个参数,告诉你要执行哪个动作(像alma一样或像citrom一样)。
答案 5 :(得分:0)
如果已知某个对象是B或C,那么多态性并不总是可行的。在这种情况下,boost::variant
通常更简洁。
话虽如此,如果你想走多态路线,记住引导设计的东西是非常重要的。
多态意味着运行时多态。即程序无法知道对象的真实类型。它也无法知道对象可能存在的全部可能类型,因为另一个开发人员可以制作一个模块代码一无所知的类型。此外,当使用Alma接口时,代码不应该需要知道更多。调用魔法,例如&#34;我知道它将是Citrom
因为bool是真的&#34;几个星期或几个月的代码维护噩梦奠定了基础。当在商业,生产代码中完成时,它会导致昂贵且令人尴尬的漏洞狩猎。别这么做。
这证明,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;
}
预期产出:
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