如何从条件中声明一个对象并使其通过函数的其余部分可用?
Posted
技术标签:
【中文标题】如何从条件中声明一个对象并使其通过函数的其余部分可用?【英文标题】:How to declare an object from a condition and make it available through the rest of the function? 【发布时间】:2010-11-29 12:57:55 【问题描述】:我有两个类,它们都具有相同的函数名称,它们根据用户输入执行类似的操作。我需要做这样的事情。
if (myapp.advanced == true)
class1 a;
else
class2 a;
但是由于 a 是从 if 内部声明的,所以它在下一行中不可用。如何解决上述情况?
a.something();
【问题讨论】:
myapp.advanced
的值在编译时是否已知?
@Steve:不,是用户在程序运行时设置的。
【参考方案1】:
我能想到的两种方法:
1) 让 class1 和 class2 派生自某个基类 classB
,然后这样做:
shared_ptr<classB> a;
if(myapp.advanced == true) a.reset(new class1);
else a.reset(new class2);
a->something();
2) 编写模板函数:
template <typename T> void do_something(T& t)
t.something();
...
if(myapp.advanced)
class1 a;
do_something(a);
else
class2 a;
do_something(a);
请注意,如果您无法更改class1
和class2
以添加基类,则第二种方法更适合。我还假设do_something
中的位比仅在相关对象上调用something()
更复杂——否则你可以直接调用它!
编辑:只是为了澄清一下,第二种方法并没有使它在所讨论的函数的其余部分中都可用——它添加了一个新函数来代替它。
【讨论】:
【参考方案2】:如果这些类型相关,请使用公共基类并执行以下操作:
const base& a = (myapp.advanced == true) ? static_cast<base&>(class1())
: class2();
a.something();
a.some_other_thing();
a.yet_another_thing();
绑定到const
引用的临时对象的生命周期会延长到引用的生命周期结束,因此这是安全的。但是,如果您将关注点分开对象创建,则不需要这样的hackery(如果您需要修改对象,您可以取消const
)和 object using 分成不同的功能:
void do_something(base& obj)
obj.something();
obj.some_other_thing();
obj.yet_another_thing();
if (myapp.advanced == true)
class1 a;
do_something(a);
else
class2 a;
do_something(a);
如果类型不相关,您仍然可以通过将do_something()
转换为函数模板来做到这一点:
template< class T >
void do_something(T& obj)
obj.something();
obj.some_other_thing();
obj.yet_another_thing();
if (myapp.advanced == true)
class1 a;
do_something(a);
else
class2 a;
do_something(a);
【讨论】:
@sbi:是的,我注意到在我评论你添加了一个不同的之后,不用担心。顺便说一句,没有强制转换,三元表达式将无法编译,因为class1()
和 class2()
没有相同的类型。其中一个需要转换为const base&
。
@sgolodetz:你说得对,感谢您指出这一点!我修好了。
顺便说一句,另一个问题是,第一种方法仅在对象可以是const
时才有效——因为您不能将临时对象绑定到非常量引用。但如果他们可以成为const
,那么这是处理事情的好方法。
@sgolodetz:你也是对的。我有点沮丧,因为const
问题是让我首先想到第二种方法的原因,但后来我完全搞砸了。 <sigh>
也许我应该学会喜欢咖啡。
@sbi:抱歉,我不是有意攻击你——我其实很喜欢你的回答,只是想指出我发现的几件事。【参考方案3】:
您的编码逻辑暗示 Class1 和 Class2 有一些共同点。通过让它们从公共基类派生来在代码中表达这一点。 然后使用基类指针来保存派生类的实例。
【讨论】:
【参考方案4】:有很多方法可以解决这个问题,但如果没有更多信息,我可能会建议您这样做:
我想这些类有共同的祖先,叫做 Base
Base* a;
if (myapp.advanced == true)
a = new class1();
else
a = new class2();
当然,当您不再需要delete
或使用智能指针时,您一定不要忘记发出它。
如果你发现自己经常重复这个 if-else 语句,这个过程可能会更好地包装在某种函数或工厂类中,但这一切都取决于具体情况。
【讨论】:
你的意思是a = new class2;
为 else 分支 :)【参考方案5】:
我建议将函数 something() 作为纯虚函数放到基类中,并从中继承 class1 和 class2。
class Base
public:
virtual void something() = 0;
virtual ~Base(); // since we use Base class pointer the destructor should be virtual
;
class class1 : public Base
public:
void something() //do stuff
;
class class2 : public Base
public:
void something() //do other stuff
;
以下是该技术的使用示例:
int main()
Base* a = NULL;
if (myapp.advanced == true)
a = new class1();
else
a = new class2();
a->something();
// when the instance is not needed anymore destroy it.
delete a;
就像在 cmets 中提到的 Fred Nurk 一样,还有其他使用 delete
运算符的替代方法 - auto_ptr,不同的 boost 智能指针。它们被许多人(包括我自己)广泛使用,从而更容易控制使用new
创建的对象的生命周期。
OP 评论后的另一个编辑: 不要忘记在标题中放置多个包含保护宏
#ifndef _SOME_UNIQUE_NAME_HERE_
#define _SOME_UNIQUE_NAME_HERE_
// header body goes here
#endif
避免将您的标头多次包含(直接或间接)到一个 cpp 中。
【讨论】:
可能想要将Base::something()
、class1::something()
和class2::something()
设为public,并为Base
添加一个虚拟析构函数。
不要使用 delete、使用 auto_ptr、unique_ptr、scoped_ptr 或替代方法。
这引入了动态分配的对象而不知道它们是否真的需要,然后传播手动内存管理。抱歉,这是我发来的-1
。
@Dimitry:OP 的问题中没有关于手动管理动态对象的内容。 你向此介绍了new
,你的回答显示了如何手动执行此操作。这就是为什么我对你的回答投了反对票。哦,那个基类的东西不一定需要一个动态对象(见我的回答)。
@sbi 我考虑了 Fred 的评论,并在答案中提到除了删除之外还有其他选项。我从来没有说过动态对象是必须的。它可以用于像这样的简单示例,希望使基类的概念更清晰。以上是关于如何从条件中声明一个对象并使其通过函数的其余部分可用?的主要内容,如果未能解决你的问题,请参考以下文章
如何让信息按钮出现并使其在 jquery mobile 或 javascript 中起作用