• C++ polymorphism Virtual Function 多态 虚函数 接口 抽象类 纯虚函数


    Polymorphism in C++ https://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm

    https://github.com/mongodb/mongo/blob/410656e971aff8f491a87337a17d04bd866389ba/src/mongo/base/initializer.cpp

    /**
     *    Copyright (C) 2018-present MongoDB, Inc.
     *
     *    This program is free software: you can redistribute it and/or modify
     *    it under the terms of the Server Side Public License, version 1,
     *    as published by MongoDB, Inc.
     *
     *    This program is distributed in the hope that it will be useful,
     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *    Server Side Public License for more details.
     *
     *    You should have received a copy of the Server Side Public License
     *    along with this program. If not, see
     *    <http://www.mongodb.com/licensing/server-side-public-license>.
     *
     *    As a special exception, the copyright holders give permission to link the
     *    code of portions of this program with the OpenSSL library under certain
     *    conditions as described in each individual source file and distribute
     *    linked combinations including the program with the OpenSSL library. You
     *    must comply with the Server Side Public License in all respects for
     *    all of the code used other than as permitted herein. If you modify file(s)
     *    with this exception, you may extend this exception to your version of the
     *    file(s), but you are not obligated to do so. If you do not wish to do so,
     *    delete this exception statement from your version. If you delete this
     *    exception statement from all source files in the program, then also delete
     *    it in the license file.
     */
    
    #include "mongo/platform/basic.h"
    
    #include "mongo/base/initializer.h"
    
    #include <iostream>
    
    #include "mongo/base/deinitializer_context.h"
    #include "mongo/base/global_initializer.h"
    #include "mongo/base/initializer_context.h"
    #include "mongo/util/assert_util.h"
    #include "mongo/util/quick_exit.h"
    
    namespace mongo {
    
    Initializer::Initializer() {}
    Initializer::~Initializer() {}
    
    Status Initializer::executeInitializers(const InitializerContext::ArgumentVector& args,
                                            const InitializerContext::EnvironmentMap& env) {
        std::vector<std::string> sortedNodes;
        Status status = _graph.topSort(&sortedNodes);
        if (Status::OK() != status)
            return status;
    
        InitializerContext context(args, env);
    
        for (size_t i = 0; i < sortedNodes.size(); ++i) {
            InitializerDependencyNode* node = _graph.getInitializerNode(sortedNodes[i]);
    
            // If already initialized then this node is a legacy initializer without re-initialization
            // support.
            if (node->isInitialized())
                continue;
    
            auto const& fn = node->getInitializerFunction();
            if (!fn) {
                return Status(ErrorCodes::InternalError,
                              "topSort returned a node that has no associated function: "" +
                                  sortedNodes[i] + '"');
            }
            try {
                status = fn(&context);
            } catch (const DBException& xcp) {
                return xcp.toStatus();
            }
    
            if (Status::OK() != status)
                return status;
    
            node->setInitialized(true);
        }
        return Status::OK();
    }
    
    Status Initializer::executeDeinitializers() {
        std::vector<std::string> sortedNodes;
        Status status = _graph.topSort(&sortedNodes);
        if (Status::OK() != status)
            return status;
    
        DeinitializerContext context{};
    
        // Execute deinitialization in reverse order from initialization.
        for (auto it = sortedNodes.rbegin(), end = sortedNodes.rend(); it != end; ++it) {
            InitializerDependencyNode* node = _graph.getInitializerNode(*it);
            auto const& fn = node->getDeinitializerFunction();
            if (fn) {
                try {
                    status = fn(&context);
                } catch (const DBException& xcp) {
                    return xcp.toStatus();
                }
    
                if (Status::OK() != status)
                    return status;
    
                node->setInitialized(false);
            }
        }
        return Status::OK();
    }
    
    Status runGlobalInitializers(const InitializerContext::ArgumentVector& args,
                                 const InitializerContext::EnvironmentMap& env) {
        return getGlobalInitializer().executeInitializers(args, env);
    }
    
    Status runGlobalInitializers(int argc, const char* const* argv, const char* const* envp) {
        InitializerContext::ArgumentVector args(argc);
        std::copy(argv, argv + argc, args.begin());
    
        InitializerContext::EnvironmentMap env;
    
        if (envp) {
            for (; *envp; ++envp) {
                const char* firstEqualSign = strchr(*envp, '=');
                if (!firstEqualSign) {
                    return Status(ErrorCodes::BadValue, "malformed environment block");
                }
                env[std::string(*envp, firstEqualSign)] = std::string(firstEqualSign + 1);
            }
        }
    
        return runGlobalInitializers(args, env);
    }
    
    Status runGlobalDeinitializers() {
        return getGlobalInitializer().executeDeinitializers();
    }
    
    void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* const* envp) {
        Status status = runGlobalInitializers(argc, argv, envp);
        if (!status.isOK()) {
            std::cerr << "Failed global initialization: " << status << std::endl;
            quickExit(1);
        }
    }
    
    }  // namespace mongo
    

      

    #include <iostream> 
    using namespace std;
     
    class Shape {
       protected:
          int width, height;
          
       public:
          Shape( int a = 0, int b = 0){
             width = a;
             height = b;
          }
          int area() {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    class Rectangle: public Shape {
       public:
          Rectangle( int a = 0, int b = 0):Shape(a, b) { }
          
          int area () { 
             cout << "Rectangle class area :" <<endl;
             return (width * height); 
          }
    };
    
    class Triangle: public Shape {
       public:
          Triangle( int a = 0, int b = 0):Shape(a, b) { }
          
          int area () { 
             cout << "Triangle class area :" <<endl;
             return (width * height / 2); 
          }
    };
    
    // Main function for the program
    int main() {
       Shape *shape;
       Rectangle rec(10,7);
       Triangle  tri(10,5);
    
       // store the address of Rectangle
       shape = &rec;
       
       // call rectangle area.
       shape->area();
    
       // store the address of Triangle
       shape = &tri;
       
       // call triangle area.
       shape->area();
       
       return 0;
    }
    

      Polymorphism in C++ https://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm

    C++ 多态 | 菜鸟教程 http://www.runoob.com/cplusplus/cpp-polymorphism.html

    C++ 多态

    多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。

    C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。

    下面的实例中,基类 Shape 被派生为两个类,如下所示:

    实例

    #include <iostream> 
    using namespace std;
     
    class Shape {
       protected:
          int width, height;
       public:
          Shape( int a=0, int b=0)
          {
             width = a;
             height = b;
          }
          int area()
          {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    class Rectangle: public Shape{
       public:
          Rectangle( int a=0, int b=0):Shape(a, b) { }
          int area ()
          { 
             cout << "Rectangle class area :" <<endl;
             return (width * height); 
          }
    };
    class Triangle: public Shape{
       public:
          Triangle( int a=0, int b=0):Shape(a, b) { }
          int area ()
          { 
             cout << "Triangle class area :" <<endl;
             return (width * height / 2); 
          }
    };
    // 程序的主函数
    int main( )
    {
       Shape *shape;
       Rectangle rec(10,7);
       Triangle  tri(10,5);
     
       // 存储矩形的地址
       shape = &rec;
       // 调用矩形的求面积函数 area
       shape->area();
     
       // 存储三角形的地址
       shape = &tri;
       // 调用三角形的求面积函数 area
       shape->area();
       
       return 0;
    }
    

      

    当上面的代码被编译和执行时,它会产生下列结果:

    Parent class area
    Parent class area

    导致错误输出的原因是,调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。

    但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:

    class Shape {
       protected:
          int width, height;
       public:
          Shape( int a=0, int b=0)
          {
             width = a;
             height = b;
          }
          virtual int area()
          {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    

      

    修改后,当编译和执行前面的实例代码时,它会产生以下结果:

    Rectangle class area
    Triangle class area

    此时,编译器看的是指针的内容,而不是它的类型。因此,由于 tri 和 rec 类的对象的地址存储在 *shape 中,所以会调用各自的 area() 函数。

    正如您所看到的,每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。

    虚函数

    虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。

    我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定

    纯虚函数

    您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。

    我们可以把基类中的虚函数 area() 改写如下:

    class Shape {
       protected:
          int width, height;
       public:
          Shape( int a=0, int b=0)
          {
             width = a;
             height = b;
          }
          // pure virtual function
          virtual int area() = 0;
    };
    

      

     

    = 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数

    The word polymorphism means having many forms. Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance.

    C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.

    Consider the following example where a base class has been derived by other two classes −

    #include <iostream> 
    using namespace std;
     
    class Shape {
       protected:
          int width, height;
          
       public:
          Shape( int a = 0, int b = 0){
             width = a;
             height = b;
          }
          int area() {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    class Rectangle: public Shape {
       public:
          Rectangle( int a = 0, int b = 0):Shape(a, b) { }
          
          int area () { 
             cout << "Rectangle class area :" <<endl;
             return (width * height); 
          }
    };
    
    class Triangle: public Shape {
       public:
          Triangle( int a = 0, int b = 0):Shape(a, b) { }
          
          int area () { 
             cout << "Triangle class area :" <<endl;
             return (width * height / 2); 
          }
    };
    
    // Main function for the program
    int main() {
       Shape *shape;
       Rectangle rec(10,7);
       Triangle  tri(10,5);
    
       // store the address of Rectangle
       shape = &rec;
       
       // call rectangle area.
       shape->area();
    
       // store the address of Triangle
       shape = &tri;
       
       // call triangle area.
       shape->area();
       
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Parent class area :
    Parent class area :
    

    The reason for the incorrect output is that the call of the function area() is being set once by the compiler as the version defined in the base class. This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. This is also sometimes called early binding because the area() function is set during the compilation of the program.

    But now, let's make a slight modification in our program and precede the declaration of area() in the Shape class with the keyword virtual so that it looks like this −

    class Shape {
       protected:
          int width, height;
          
       public:
          Shape( int a = 0, int b = 0) {
             width = a;
             height = b;
          }
          virtual int area() {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    

    After this slight modification, when the previous example code is compiled and executed, it produces the following result −

    Rectangle class area
    Triangle class area
    

    This time, the compiler looks at the contents of the pointer instead of it's type. Hence, since addresses of objects of tri and rec classes are stored in *shape the respective area() function is called.

    As you can see, each of the child classes has a separate implementation for the function area(). This is how polymorphism is generally used. You have different classes with a function of the same name, and even the same parameters, but with different implementations.

    Virtual Function

    A virtual function is a function in a base class that is declared using the keyword virtual. Defining in a base class a virtual function, with another version in a derived class, signals to the compiler that we don't want static linkage for this function.

    What we do want is the selection of the function to be called at any given point in the program to be based on the kind of object for which it is called. This sort of operation is referred to as dynamic linkage, or late binding.

    Pure Virtual Functions

    It is possible that you want to include a virtual function in a base class so that it may be redefined in a derived class to suit the objects of that class, but that there is no meaningful definition you could give for the function in the base class.

    We can change the virtual function area() in the base class to the following −

    class Shape {
       protected:
          int width, height;
    
       public:
          Shape(int a = 0, int b = 0) {
             width = a;
             height = b;
          }
          
          // pure virtual function
          virtual int area() = 0;
    };
    

    The = 0 tells the compiler that the function has no body and above virtual function will be called pure virtual function.

    C++ 接口(抽象类)

    接口描述了类的行为和功能,而不需要完成类的特定实现。

    C++ 接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念。

    如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 "= 0" 来指定的,如下所示:

    class Box
    {
       public:
          // 纯虚函数
          virtual double getVolume() = 0;
       private:
          double length;      // 长度
          double breadth;     // 宽度
          double height;      // 高度
    };
    

      

    设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。

    因此,如果一个 ABC 的子类需要被实例化,则必须实现每个虚函数,这也意味着 C++ 支持使用 ABC 声明接口。如果没有在派生类中重写纯虚函数,就尝试实例化该类的对象,会导致编译错误。

    可用于实例化对象的类被称为具体类

    抽象类的实例

    请看下面的实例,基类 Shape 提供了一个接口 getArea(),在两个派生类 Rectangle 和 Triangle 中分别实现了 getArea()

    实例

    #include <iostream>
     
    using namespace std;
     
    // 基类
    class Shape 
    {
    public:
       // 提供接口框架的纯虚函数
       virtual int getArea() = 0;
       void setWidth(int w)
       {
          width = w;
       }
       void setHeight(int h)
       {
          height = h;
       }
    protected:
       int width;
       int height;
    };
     
    // 派生类
    class Rectangle: public Shape
    {
    public:
       int getArea()
       { 
          return (width * height); 
       }
    };
    class Triangle: public Shape
    {
    public:
       int getArea()
       { 
          return (width * height)/2; 
       }
    };
     
    int main(void)
    {
       Rectangle Rect;
       Triangle  Tri;
     
       Rect.setWidth(5);
       Rect.setHeight(7);
       // 输出对象的面积
       cout << "Total Rectangle area: " << Rect.getArea() << endl;
     
       Tri.setWidth(5);
       Tri.setHeight(7);
       // 输出对象的面积
       cout << "Total Triangle area: " << Tri.getArea() << endl; 
     
       return 0;
    }
    

      

    当上面的代码被编译和执行时,它会产生下列结果:

    Total Rectangle area: 35
    Total Triangle area: 17

    从上面的实例中,我们可以看到一个抽象类是如何定义一个接口 getArea(),两个派生类是如何通过不同的计算面积的算法来实现这个相同的函数。

    设计策略

    面向对象的系统可能会使用一个抽象基类为所有的外部应用程序提供一个适当的、通用的、标准化的接口。然后,派生类通过继承抽象基类,就把所有类似的操作都继承下来。

    外部应用程序提供的功能(即公有函数)在抽象基类中是以纯虚函数的形式存在的。这些纯虚函数在相应的派生类中被实现。

    这个架构也使得新的应用程序可以很容易地被添加到系统中,即使是在系统被定义之后依然可以如此。

    An interface describes the behavior or capabilities of a C++ class without committing to a particular implementation of that class.

    The C++ interfaces are implemented using abstract classes and these abstract classes should not be confused with data abstraction which is a concept of keeping implementation details separate from associated data.

    A class is made abstract by declaring at least one of its functions as pure virtual function. A pure virtual function is specified by placing "= 0" in its declaration as follows −

    class Box {
       public:
          // pure virtual function
          virtual double getVolume() = 0;
          
       private:
          double length;      // Length of a box
          double breadth;     // Breadth of a box
          double height;      // Height of a box
    };
    

    The purpose of an abstract class (often referred to as an ABC) is to provide an appropriate base class from which other classes can inherit. Abstract classes cannot be used to instantiate objects and serves only as an interface. Attempting to instantiate an object of an abstract class causes a compilation error.

    Thus, if a subclass of an ABC needs to be instantiated, it has to implement each of the virtual functions, which means that it supports the interface declared by the ABC. Failure to override a pure virtual function in a derived class, then attempting to instantiate objects of that class, is a compilation error.

    Classes that can be used to instantiate objects are called concrete classes.

    Abstract Class Example

    Consider the following example where parent class provides an interface to the base class to implement a function called getArea() −

    #include <iostream>
     
    using namespace std;
     
    // Base class
    class Shape {
       public:
          // pure virtual function providing interface framework.
          virtual int getArea() = 0;
          void setWidth(int w) {
             width = w;
          }
       
          void setHeight(int h) {
             height = h;
          }
       
       protected:
          int width;
          int height;
    };
     
    // Derived classes
    class Rectangle: public Shape {
       public:
          int getArea() { 
             return (width * height); 
          }
    };
    
    class Triangle: public Shape {
       public:
          int getArea() { 
             return (width * height)/2; 
          }
    };
     
    int main(void) {
       Rectangle Rect;
       Triangle  Tri;
     
       Rect.setWidth(5);
       Rect.setHeight(7);
       
       // Print the area of the object.
       cout << "Total Rectangle area: " << Rect.getArea() << endl;
    
       Tri.setWidth(5);
       Tri.setHeight(7);
       
       // Print the area of the object.
       cout << "Total Triangle area: " << Tri.getArea() << endl; 
    
       return 0;
    }

    When the above code is compiled and executed, it produces the following result −

    Total Rectangle area: 35
    Total Triangle area: 17
    

    You can see how an abstract class defined an interface in terms of getArea() and two other classes implemented same function but with different algorithm to calculate the area specific to the shape.

    Designing Strategy

    An object-oriented system might use an abstract base class to provide a common and standardized interface appropriate for all the external applications. Then, through inheritance from that abstract base class, derived classes are formed that operate similarly.

    The capabilities (i.e., the public functions) offered by the external applications are provided as pure virtual functions in the abstract base class. The implementations of these pure virtual functions are provided in the derived classes that correspond to the specific types of the application.

    This architecture also allows new applications to be added to a system easily, even after the system has been defined.

    Interfaces in C++ (Abstract Classes) - Tutorialspoint https://www.tutorialspoint.com/cplusplus/cpp_interfaces.htm

  • 相关阅读:
    解决winXP无法远程桌面连到win8
    Exception处理
    Java父类与子类的内存引用讲解
    JAVA子类继承父类
    JAVA子类调用父类构造方法
    JS 矩阵转置
    JS 二分查找
    JS冒泡排序
    JS 求平均值
    关于STM32 NVIC配置的解释
  • 原文地址:https://www.cnblogs.com/rsapaper/p/10190965.html
Copyright © 2020-2023  润新知