我正在尝试利用c ++中的多态性,但我来自c世界,我认为我所做的事情可以通过OOP方式更加巧妙地完成。
我有2个具有完全相同的公共属性的类,我想“隐藏”存在2个不同的实现。这样我可以有一个单独的类,我可以使用成员函数,如果我正在访问特定的类。
我想要完成的一个非常简单的实现如下:
#include <iostream>
class subber{
private:
int id;
public:
int doStuff(int a,int b) {return a-b;};
};
class adder{
private:
int id;
public:
int doStuff(int a, int b) {return a+b;};
};
class wrapper{
private:
int type_m;
adder cls1;
subber cls2;
public:
wrapper(int type) {type_m=type;};//constructor
int doStuff(int a, int b) {if(type_m==0) return cls1.doStuff(a,b); else return cls2.doStuff(a,b);};
};
int main(){
wrapper class1(0);
std::cout <<class1.doStuff(1,3) <<std::endl;
wrapper class2(1);
std::cout <<class2.doStuff(1,3) <<std::endl;
return 0;
}
我有两个名为“subber”和“adder”的类,它们都有一个名为doStuff的成员函数,它将减去添加2个数字。
这包含在一个类“wrapper”中,它包含“adder”和“subber”作为私有变量,以及一个doStuff公共成员函数。并且给定了我的“包装器”类的实例化值,我的“包装器”类将简单地将“doStuff”传递给正确的类。
这段代码确实有用,但我想避免在我的包装器类中设置“subber”和“adder”,因为我只需要在每个“包装器”类中使用它们。
由于
答案 0 :(得分:3)
有很多方法可以做到这一点。例如,通过Factory。
但是要保持简单 - 创建一个定义接口的基本抽象类,并从中派生类来实现功能。然后你只需要进行一次区分,当你创建类时,在你不关心之后,你只需要调用接口函数。
你的代码看起来就像那样。
class DoStuffer
{
public:
virtual int doStuff(int, int)=0;
virtual ~DoStuffer(){}; // Because Tony insists:-) See the comments
}
class subber: public DoStuffer{
public:
virtual int doStuff(int a,int b) {return a-b;};
};
class adder: public DoStuffer{
public:
virtual int doStuff(int a, int b) {return a+b;};
};
int main(){
DoStuffer *class1 = new adder();
DoStuffer *class2 = new subber();
std::cout <<class1->doStuff(1,3) <<std::endl;
std::cout <<class2->doStuff(1,3) <<std::endl;
delete class1; // don't forget these:-)
delete class2;
return 0;
}
答案 1 :(得分:1)
经典的运行时多态方法是:
struct Operation
{
virtual ~Operation() { } // guideline: if there are any virtual functions,
// provide virtual destructor
virtual int doStuff(int, int) const;
};
struct Subber : Operation
{
int doStuff(int a, int b) const { return a - b; }
};
struct Adder : Operation
{
int doStuff(int a, int b) const { return a + b; }
};
enum Operations { Add, Subtract };
struct Operation* op_factory(Operations op)
{
if (op == Add) return new Adder;
if (op == Subtract) return new Subber;
throw std::runtime_error("unsupported op");
}
int main()
{
Operation* p1 = op_factory(Add);
std::cout << p1->doStuff(1,3) <<std::endl;
Operation* p2 = op_factory(Subtract);
std::cout << p2->doStuff(1,3) <<std::endl;
delete p1;
delete p2;
}
从标准5.3.5 / 5 “在第一个备选(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数动态的基类type和static类型应该有一个虚析构函数,或者行为是未定义的。“,这就是你必须在基类析构函数上使用virtual
关键字的原因。
值得注意的是,在您的示例中,要使用函数参数0或1将要执行的操作类型传递给包装类...这就是您希望运行时多态性的原因。例如,如果0或1值基于命令行参数,文件内容,键盘输入等,则上面的工厂方法可以传递相应的Add或Subtract值,并接收从Operation派生的适当行为的对象。这种基于运行时值创建运行时多态类型实例的概念称为工厂。
如果你真的只需要编译时多态,你可以用以下模板做一些有趣的事情:
template <class Operation>
void output(int a, int b)
{
std::cout << Operation::doStuff(a, b) << std::endl;
std::cout << Operation::doStuff(a * 10, b * 10) << std::endl;
std::cout << Operation::doStuff(a * 100, b * 100) << std::endl;
}
int main()
{
output<adder>(1, 3);
output<subber>(1, 3);
}
FWIW,您的方法可能比虚拟函数方法稍快(因为它可能会更多地内联),但不是干净,可扩展,可维护或可扩展。
答案 2 :(得分:1)
这是使用C ++类系统来实现所需内容的更惯用的方法之一。 adder
和subber
都公开继承自wrapper
,现在是一个抽象基类。 doStuff
方法现在是一个(纯)虚函数。而不是wrapper
的简单实例,“封装”对象现在是对wrapper
的引用。
#include <iostream>
class wrapper {
public:
virtual int doStuff(int a, int b) = 0;
};
class subber : public wrapper {
public:
virtual int doStuff(int a,int b) {return a - b;}
};
class adder : public wrapper {
public:
virtual int doStuff(int a, int b) {return a + b;}
};
int main(){
// actual objects
adder impl1;
subber impl2;
// in real code, the wrapper references would probably be function arguments
wrapper& class1 = impl1;
std::cout << class1.doStuff(1,3) << std::endl;
wrapper& class2 = impl2;
std::cout << class2.doStuff(1,3) << std::endl;
return 0;
}
(在这个例子中没有使用任何工厂模式,因为它不是显而易见的,或者问题是什么。)
答案 3 :(得分:1)
完全是上次说的。
创建基类,并具有虚函数| doStuff |在它。
然后你可以从中派生出任意数量的类,都必须以他们想要的方式实现上述虚函数。
然后您可以执行以下操作
BaseClass *object1 = new DerivedClass1();
BaseClass *object2 = new DerivedClass2();
..
你甚至可以做
object1 = object2;
然后他们指向同一个对象(即类型为| DerivedClass2 |的对象)
但请记住,当你执行objectn->doStuff()
时,将执行的函数将是指针在运行时指向的函数,而不是在编译时指向的函数。
即。如果我做object1->doStuff()
DerivedClass2的doStuff将被调用,因为我们已经做过`object1 = object2;
您可能想要Google阅读
多态性/运行时多态性 C ++中的虚函数
您可以阅读工厂方法,这是一种被称为设计模式的东西,但在以后的生活中。
由于
答案 4 :(得分:0)
我认为您正在寻找的是虚拟功能。如果在基类中声明一个虚函数,则可以执行诸如创建包含从基类派生的多个对象的向量之类的操作,但是当您调用特定对象时,它将执行它自己的方法。