多态性和类的封装

时间:2011-06-07 03:27:22

标签: c++ inheritance polymorphism encapsulation

我正在尝试利用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”的类,它们都有一个名为doS​​tuff的成员函数,它将减去添加2个数字。

这包含在一个类“wrapper”中,它包含“adder”和“subber”作为私有变量,以及一个doStuff公共成员函数。并且给定了我的“包装器”类的实例化值,我的“包装器”类将简单地将“doStuff”传递给正确的类。

这段代码确实有用,但我想避免在我的包装器类中设置“subber”和“adder”,因为我只需要在每个“包装器”类中使用它们。

由于

5 个答案:

答案 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 ++类系统来实现所需内容的更惯用的方法之一。 addersubber都公开继承自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)

我认为您正在寻找的是虚拟功能。如果在基类中声明一个虚函数,则可以执行诸如创建包含从基类派生的多个对象的向量之类的操作,但是当您调用特定对象时,它将执行它自己的方法。