假设我有4个班级:
所有孩子都是班级家长的后代。
在我的玩具程序中,我必须为每个孩子创建一个单独的变量,然后处理需要处理的内容。但是我希望有一个父类型的变量可以作为一个子进行转换。
这是我目前的解决方案:
int main(int argc, char* argv[]) {
Child1 c1 = Child1();
Child2 c2 = Child2();
Child3 c3 = Child3();
switch(arg[1]) {
case CHILD1:
c1.start();
break;
case CHILD2:
c2.start();
break;
case CHILD3:
c3.start();
break;
}
return 0;
}
以下是我希望获得的解决方案类型:
int main(int argc, char* argv[]) {
Parent p = Parent();
switch(arg[1]) {
case CHILD1:
(Child1)p.start();
break;
case CHILD2:
(Child2)p.start();
break;
case CHILD3:
(Child3)p.start();
break;
}
return 0;
}
我知道上面的代码不正确。但我认为它恰当地传达了我想要达到的目标。我不想浪费内存来创建以前没用的对象。
答案 0 :(得分:3)
创意一:在交换机中创建项目
int main(int argc, char* argv[]) {
switch(arg[1]) {
case CHILD1:
{
Child1 p;
p.start();
break;
}
case CHILD2:
{
Child2 p;
p.start();
break;
}
case CHILD3:
{
Child3 p;
p.start();
break;
}
}
return 0;
}
好像很多代码都是复制粘贴的吗?对。如果您的Parent
具有虚拟析构函数和虚拟start
方法,则可以使用工厂模式,从而最大限度地减少重复。
std::unique_ptr<Parent> child_factory(char*) {
switch(arg[1]) {
case CHILD1: return std::make_unique<Child1>();
case CHILD2: return std::make_unique<Child2>();
case CHILD3: return std::make_unique<Child3>();
default: throw std::runtime_error("invalid child type");
}
}
int main(int argc, char* argv[]) {
std::unique_ptr<Parent> p = child_factory(arg[1]);
p->start();
return 0;
}
答案 1 :(得分:1)
如果这些物品不需要长寿,那么你可以这样做:
switch(arg[1]) {
case CHILD1:
{
Child1 c1;
c1.start();
break;
}
case CHILD2:
{
Child2 c2;
c2.start();
break;
}
case CHILD3:
{
Child3 c3;
c3.start();
break;
}
}
另一方面,如果您需要保留更长时间并且使用Parent
类型,那么您需要查看分配给基类型指针的动态分配对象。在这种情况下,您可能希望start
方法为virtual
。然后你可以这样做:
Parent* p = NULL;
switch(arg[1]) {
case CHILD1:
p = new Child1;
break;
case CHILD2:
p = new Child2;
break;
case CHILD3:
p = new Child3;
break;
}
p.start();
// more stuff
delete p;
当然,这里还有很大的改进空间,例如处理arg[1]
与任何情况都不匹配的情况。最佳做法是使用p
的智能指针,以便更可靠地处理释放。
答案 2 :(得分:0)
投射语法不是(Child)p.start()
,而是((Child)p).start()
。前者意味着(Child) (p.start())
所以它会抛出start返回的值,而不是P。
无论如何,完全不需要施法,因为所有这些都来自“父母”。阅读虚拟方法。有了它们,您可以执行以下操作:
Parent p = ...
p.start(); // the virtual method 'start' takes care of calling the right code
然而#1:没有免费的午餐。虚拟方法可以确保在您调用“开始”时调用孩子的方法。在父级,但仍然必须选择正确的child1 / child2 / child3,具体取决于arg [1]。
Parent p = chooseTheChild( arg[1] ); // you need to write it..
p.start(); // the virtual method 'start' takes care of calling the right code
然而#2:它不适用于普通父母。虚拟方法适用于指针。
Parent* p = chooseTheChild( arg[1] ); // you need to write it..
p->start(); // the virtual method 'start' takes care of calling the right code
现在你可以写下选择&#39;功能..再没有免费午餐,仍然是一个开关。由于需要指针,你必须new
孩子:
class Parent
{
public:
~Parent() { }
virtual void start() = 0;
};
class Child1 : public Parent
{
public:
virtual void start() { std::cout << "start1!" << std::endl; }
};
class Child2 : public Parent
{
public:
virtual void start() { std::cout << "start2!" << std::endl; }
};
class Child3 : public Parent
{
public:
virtual void start() { std::cout << "start3!" << std::endl; }
};
Parent* chooseTheChild( ChildType ttt)
{
switch(ttt) {
case CHILD1: return new Child1();
case CHILD2: return new Child2();
case CHILD3: return new Child3();
}
}
.. somewhere ...
Parent* p = chooseTheChild( arg[1] );
p->start(); // the virtual method 'start' takes care of calling the right code
delete p; // new'ed? delete it when finished!
此代码是草图,并不是100%正确和干净,但应该给你一些东西。例如,显然需要智能指针而不是普通指针等等。
答案 3 :(得分:0)
对不起,但这绝对认为继承是错误的。可以考虑 parent 和 children 之间的关系: child_object 是 < em> parent_object ,这意味着 child_object 也可以用作 parent_object ,即a可以被投放,被称为......一个但反之亦然!
Mooing Duck的第二个例子是好东西。
答案 4 :(得分:0)
显而易见的解决方案就是在需要时创建孩子。如果您愿意,可以使用函数模板来消除重复的代码:
#include <iostream>
struct Child1{
void start() { std::cout << "Start Child1\n"; }
};
struct Child2{
void start() { std::cout << "Start Child2\n"; }
};
struct Child3{
void start() { std::cout << "Start Child3\n"; }
};
template<typename Child>
void start() {
auto child = Child();
child.start();
}
int main(int /*argc*/, char* argv[]) {
auto type = std::string(argv[1]);
if (type == "CHILD1")
start<Child1>();
else if (type == "CHILD2")
start<Child2>();
else if (type == "CHILD3")
start<Child3>();
}
在这种特殊情况下,如果您不想使用virtual
方法,则在一个更复杂的情况下,您可能希望拥有一个返回({智能)指针的工厂{{1在Parent
上有一个虚拟的析构函数和启动方法。