简体   繁体   English

类的多态性和封装

[英]polymorphism and encapsulation of classes

I'm trying to take advantage of the polymorphism in c++, but I'm from a c world, and I think what I've done could be done more cleverly in a OOP way.我正在尝试利用 c++ 中的多态性,但我来自 c 世界,我认为我所做的事情可以用 ZCE4195DA808656BEAE0C97FED91949 的方式更巧妙地完成。

I have 2 classes that has exactly the same public attributes, and I want to "hide" that there exists 2 different implementations.我有 2 个具有完全相同公共属性的类,我想“隐藏”存在 2 个不同的实现。 Such that I can have a single class where I can use the member functions as If i were accessing the specific class.这样我就可以拥有一个 class,我可以在其中使用成员函数,就像我正在访问特定的 class 一样。

An very simple implementation of what I'm trying to accomplish is below:我想要完成的一个非常简单的实现如下:

#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;
}

I have 2 classes called "subber" and "adder" which both have a member function called doStuff, which will either subtract of add 2 numbers.我有 2 个名为“subber”和“adder”的类,它们都有一个名为 doStuff 的成员 function,它将减去两个数字。

This I wrap up in a class "wrapper", which has both "adder" and "subber" as private variables, and a doStuff public member function.我将其封装在一个 class“包装器”中,它同时具有“adder”和“subber”作为私有变量,以及一个 doStuff 公共成员 function。 And given which value I instantiate my "wrapper" class with, my "wrapper" class will simply relay the "doStuff" to the correct class.鉴于我用哪个值实例化我的“包装器”class,我的“包装器”class 将简单地将“doStuff”中继到正确的 class。

This code does of cause work, but I would like to avoid instatiating both "subber" and "adder" in my wrapper class, since I will only need of them in each of my "wrapper" classes.这段代码确实有效,但我想避免在我的包装器 class 中同时启用“subber”和“adder”,因为我只需要在每个“包装器”类中使用它们。

Thanks谢谢

There are many ways to do it.有很多方法可以做到这一点。 Through a Factory for example.工厂为例。

But to keep it simple - make a base abstract class that defines the interface, and derive your classes from it to implement the functionality.但为了简单起见 - 创建一个基本抽象 class 定义接口,并从中派生您的类以实现功能。 Then you only need to make the distinction once, when you create the class, after that you don't care, you just call the interface functions.那么你只需要区分一次,当你创建class的时候,你就不管了,调用接口函数就可以了。

your code would look something like that.你的代码看起来像这样。

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;
}

The classic run-time polymorphic approach is:经典的运行时多态方法是:

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;
}

From the Standard 5.3.5/5 "In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor or the behavior is undefined." From the Standard 5.3.5/5 "In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall有一个虚拟析构函数或行为未定义。” , which is why you must use the virtual keyword on the base class destructor. ,这就是为什么必须在基本 class 析构函数上使用virtual关键字的原因。

It's noteworthy that in your example the type of operation to perform was communicated to the wrapper class using a function argument of 0 or 1... this is what suggests you want run-time polymorphism.值得注意的是,在您的示例中,使用 0 或 1 的 function 参数将要执行的操作类型传达给包装器 class ......这表明您需要运行时多态性。 For example, if the 0 or 1 value was based on a command line argument, file content, keyboard input etc., then the factory method above can pass a corresponding Add or Subtract value and receive an appropriately-behaving object derived from Operation.例如,如果 0 或 1 值基于命令行参数、文件内容、键盘输入等,那么上面的工厂方法可以传递相应的 Add 或 Subtract 值并接收从 Operation 派生的行为适当的 object。 This concept of creating an instance of a run-time polymorphic type based on run-time values is known as a factory.这种基于运行时值创建运行时多态类型实例的概念称为工厂。

If you really only need compile-time polymorphism, you can do some interesting things with templates such as:如果你真的只需要编译时多态,你可以用模板做一些有趣的事情,比如:

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, your approach is probably slightly faster than the virtual function approach (as it can potentially do more inlining), but not as clean, extensible, maintainable or scalable. FWIW,您的方法可能比虚拟 function 方法稍快(因为它可能会做更多内联),但不如干净、可扩展、可维护或可扩展。

This is one of the more idiomatic ways to use the C++ class system to accomplish what you want.这是使用 C++ class 系统来完成您想要的更惯用的方法之一。 Both adder and subber publicly inherit from wrapper , which is now an abstract base class. addersubber都从wrapper公开继承,它现在是一个抽象基础 class。 The doStuff method is now a (pure) virtual function. doStuff方法现在是(纯)虚拟 function。 And instead of being a simple instance of wrapper , the "encapsulated" object is now a reference to a wrapper . “封装” object 现在不再是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;
}

(Not using any factory pattern in this example, since it's not obvious that it's needed or what the question is about.) (在这个例子中没有使用任何工厂模式,因为它的需要或者问题是关于什么的并不明显。)

Exactly what was last said.正是最后所说的。

Make a base class, and have a virtual function |doStuff|制作一个基础 class,并拥有一个虚拟 function |doStuff| in it.在里面。

Then you can derive any number of classes out from it, all have to implement the above virtual function, in whatever way they want to.然后你可以从中派生出任意数量的类,都必须以他们想要的任何方式实现上述虚拟 function。

Then you can just do the following然后您可以执行以下操作

BaseClass *object1 = new DerivedClass1();
BaseClass *object2 = new DerivedClass2();
..

You can even do你甚至可以做

object1 = object2;

And then they point to the same object (ie an object of type |DerivedClass2|)然后它们指向相同的 object(即 |DerivedClass2| 类型的 object)

But remember, when you do objectn->doStuff() , the function that will be executed will be what the pointer points to at run-time, and not at compile time.但是请记住,当您执行objectn->doStuff()时,将执行的 function 将是指针在运行时指向的内容,而不是在编译时。

ie if I do object1->doStuff() DerivedClass2's doStuff will be called because we already did `object1 = object2;即如果我执行object1->doStuff() DerivedClass2 的 doStuff 将被调用,因为我们已经执行了 `object1 = object2;

You may want to Google and read about您可能想谷歌并阅读

Polymorphism/ Run-time Polymorphism Virtual Functions in C++ C++中的多态/运行时多态虚函数

You can read Factory Method, which is something that is known as a Design Pattern, but later in life.您可以阅读工厂方法,它被称为设计模式,但在以后的生活中。

Thanks谢谢

I think what you're looking for is virtual functions.我认为您正在寻找的是虚拟功能。 If you declare a function virtual in your base class, you can do things like make a vector containing multiple objects derived from your base class, but when you call on a particular object it will execute it's own method. If you declare a function virtual in your base class, you can do things like make a vector containing multiple objects derived from your base class, but when you call on a particular object it will execute it's own method.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM