• c语言实现面向对象OOC


          这种问题比较锻炼思维,同时考察c和c++的掌握程度。如果你遇到过类似问题,此题意义自不必说。如果用c实现c++,主要解决如何实现封装,继承和多态三大问题,本文分两块说。

    1、封装

    // Example class A contains regular and 
    // static member variables and methods.
    
    class A
    {
    private:
      int m_x;
      static int g_y;
      int m_z;
    
      // Should be invoked when the object ends
      void InformEnd();
    
    public:
      A(int x);
      ~A();
      void UpdateX(int newX);
      static void UpdateY(int newY);
    };
    
    // Initialization of the static variable
    int A::g_y = 0;
    
    // The non-static member variables 
    // are initialized in the constructor
    A::A(int x)
    {
      m_x = x;
      m_z = 0;
    }
    
    // Destructor invokes a private variable
    A::~A()
    {
      InformEnd();
    }
    
    // UpdateX checks the value of X against  a static variable before updating the value
    void A::UpdateX(int newX)
    {
      if (g_y != 0 && m_x < newX)
      {
        m_x = newX;
      }
    }
    
    // Unconditional update of static variable m_y
    void A::UpdateY(int newY)
    {
      g_y = newY;
    }
    
    main()
    {
        // Create a object on the heap
        A *pA = new A(5);
    
        // Create an object on the stack
        A a(6);
    
        // Example of an access via a pointer
        pA->UpdateX(8);
    
        // Example of a direct access
        a.UpdateX(9);
    
        // Example of static method call
        A::UpdateY(1000);
    
        // Deleting the object
        delete pA;
    } 
    /*
    This code maps from the C++ code to the equivalent C code.
    Mapping of the following entities is covered:
    - classes                 - methods
    - this pointer            - member variables
    - constructors            - static methods
    - destructors             - static variables
    */
     
    #include <stdio.h>
    #include <stdlib.h>
    #define TRUE 1
    #define FALSE 0
    typedef int BOOLEAN;
     
    /*
    Structure A represents the class A. Only the non-static member
    variables are present in the structure
    */
    struct A
    {
      int m_x;
      int m_z;
    };
     
    /* Notice that g_y is not a part of struct A. Its a separate global variable. */
    int g_y = 0;
     
    /*
    Prototype for the InformEnd method. The C++ version of this method
    did not have any parameters but the C mapped function needs the this
    pointer to obtain the address of the object. Note that all non-static
    methods in the C++ code would map to a C function the additional this
    pointer as the first parameter.
    */
    void InformEnd(A *this_ptr);
     
    /*
    The constructor maps to function with the this pointer and the size of the
    structure as parameters. this_ptr passed to the constructor is NULL when
    the operator new is used to create the object. this_ptr contains a valid
    pointer if the memory for the object to be constructed is already
    allocated. (e.g. local variable or part of another structure.)
    */
    A *A_Constructor(A *this_ptr, int x)
    {
      /*Check if memory has been allocated for struct A. */
      if (this_ptr == NULL)
      {
        /*Allocate memory of size A. */
        this_ptr = (A *) malloc(sizeof(A));
      }
     
      /* Once the memory has been allocated for A, initialise members of A. */
      if (this_ptr)
      {
        this_ptr->m_x = x;
        this_ptr->m_z = 0;
      }
      return this_ptr;
    }
     
    /*
    The following function is equivalent to a destructor. The this
    pointer and a dynamic flag are passed as the two parameters to
    this function. The dynamic flag is set to true if the object is
    being deleted using the delete operator.
    */
    void A_Destructor(A *this_ptr, BOOLEAN dynamic)
    {
      InformEnd(this_ptr);
     
      /* If the memory was dynamically allocated for A, explicitly free it. */
      if (dynamic)
      {
        free(this_ptr);
      }
    }
     
    /*
    A pointer this is passed as first argument. All member variables
    in the code will be accessed through an indirecion from the this
    pointer. Notice that static variables are accessed directly as
    they do not belong to any instance.
    */
    void A_UpdateX(A *this_ptr, int newX)
    {
      if (g_y != 0 && this_ptr->m_x < newX)
      {
        this_ptr->m_x = newX;
      }
    }
     
    /*
    Notice that this is not passed here. This is so because
    A_UpdateY is a static function. This function can only access
    other static functions and static or global variables. This
    function cannot access any member variables or methods of class A
    as a static function does not correspond to an instance.
    */
    void A_UpdateY(int newY)
    {
      g_y = newY;
    }
     
    main()
    {
        /*
        Dynamically allocate memory by passing NULL in this arguement.
        Also initialize members of struct pointed to by pA.
        */
        A *pA = A_Constructor(NULL, 5);
     
        /* Define local variable a of type struct A. */
        A a;
     
        /*
        Initialize members of struct variable a. Note that the
        constructor is called with the address of the object as
        a has been pre-allocated on the stack.
        */
        A_Constructor(&a, 6);
     
        /*
        Method invocations in C++ are handled by calling the
        corresponding C functions with the object pointer.
        */
        A_UpdateX(pA, 8);
        A_UpdateX(&a, 9);
     
        /* UpdateY is a static method, so object pointer is not passed */
        A_UpdateY(1000);
     
        /*
        Delete memory pointed to by pA (explicit delete in
        original code).
        */
        A_Destructor(pA, TRUE);
     
        /*
        Since memory was allocated on the stack for local struct 
        variable a, it will be deallocated when a goes out of scope.
        The destructor will also be invoked. Notice that dynamic flag
        is set to false so that the destructor does not try to
        free memory.
        */
        A_Destructor(&a, FALSE);
    }

    2、继承/多态

    // A typical example of inheritance and virtual function use.
    // We would be mapping this code to equivalent C.
     
    // Prototype graphics library function to draw a circle
    void glib_draw_circle (int x, int y, int radius);
     
    // Shape base class declaration
    class Shape
    {
    protected:
      int m_x;    // X coordinate
      int m_y;  // Y coordinate
     
    public:
      // Pure virtual function for drawing
      virtual void Draw() = 0; 
     
      // A regular virtual function
      virtual void MoveTo(int newX, int newY);
     
      // Regular method, not overridable.
      void Erase();
     
      // Constructor for Shape
      Shape(int x, int y);
     
      // Virtual destructor for Shape
      virtual ~Shape();
    };
     
    // Circle class declaration
    class Circle : public Shape
    {
    private:
       int m_radius;    // Radius of the circle
     
    public:
       // Override to draw a circle
       virtual void Draw();   
     
       // Constructor for Circle
       Circle(int x, int y, int radius);
     
       // Destructor for Circle
       virtual ~Circle();
    };
     
    // Shape constructor implementation
    Shape::Shape(int x, int y)
    {
       m_x = x;
       m_y = y;
    }
     
    // Shape destructor implementation
    Shape::~Shape()
    {
    //...
    }
     
    // Circle constructor implementation
    Circle::Circle(int x, int y, int radius) : Shape (x, y)
    {
       m_radius = radius;
    }
     
    // Circle destructor implementation
    Circle::~Circle()
    {
    //...
    }
     
    // Circle override of the pure virtual Draw method.
    void Circle::Draw()
    {
       glib_draw_circle(m_x, m_y, m_radius);
    }
     
    main()
    {
      // Define a circle with a center at (50,100) and a radius of 25
      Shape *pShape = new Circle(50, 100, 25);
     
      // Define a circle with a center at (5,5) and a radius of 2
      Circle aCircle(5,5, 2);
     
      // Various operations on a Circle via a Shape pointer
      pShape->Draw();
      pShape->MoveTo(100, 100);
      pShape->Erase();
      delete pShape;
     
      // Invoking the Draw method directly
      aCircle.Draw();
    }
    
    /*
    C code
    The following code maps the C++ code for the Shape and Circle classes
    to C code.
    */
     
    #include <stdio.h>
    #include <stdlib.h>
    #define TRUE 1
    #define FALSE 0
    typedef int BOOLEAN;
     
    /*
    Error handler used to stuff dummy VTable
    entries. This is covered later.
    */
    void pure_virtual_called_error_handler();
     
    /* Prototype graphics library function to draw a circle */
    void glib_draw_circle (int x, int y, int radius);
     
    typedef void (*VirtualFunctionPointer)(...);
     
    /*
    VTable structure used by the compiler to keep
    track of the virtual functions associated with a class.
    There is one instance of a VTable for every class
    containing virtual functions. All instances of
    a given class point to the same VTable.
    */
    struct VTable
    {
       /*
       d and i fields are used when multiple inheritance and virtual
       base classes are involved. We will be ignoring them for this
       discussion.
       */
       int d;
       int i;
     
       /*
       A function pointer to the virtual function to be called is
       stored here.
       */
       VirtualFunctionPointer pFunc;
    };
     
    /*
    The Shape class maps into the Shape structure in C. All
    the member variables present in the class are included
    as structure elements. Since Shape contains a virtual
    function, a pointer to the VTable has also been added.
    */
     
    struct Shape
    {
      int m_x;
      int m_y;
     
      /*
      The C++ compiler inserts an extra pointer to a vtable which
      will keep a function pointer to the virtual function that
      should be called.
      */
      VTable *pVTable;
    };
     
    /*
    Function prototypes that correspond to the C++ methods
    for the Shape class,
    */
    Shape *Shape_Constructor(Shape *this_ptr, int x, int y);
    void Shape_Destructor(Shape *this_ptr, bool dynamic);
    void Shape_MoveTo(Shape *this_ptr, int newX, int newY);
    void Shape_Erase(Shape *this_ptr);
     
    /*
    The Shape vtable array contains entries for Draw and MoveTo
    virtual functions. Notice that there is no entry for Erase,
    as it is not virtual. Also, the first two fields for every
    vtable entry are zero, these fields might have non zero
    values with multiple inheritance, virtual base classes
    A third entry has also been defined for the virtual destructor
    */
     
    VTable VTableArrayForShape[] =
    {
        /*
        Vtable entry virtual function Draw.
        Since Draw is pure virtual, this entry
        should never be invoked, so call error handler
        */
        { 0, 0, (VirtualFunctionPointer) pure_virtual_called_error_handler },
     
        /*
        This vtable entry invokes the base class's
        MoveTo method.
        */
        { 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
     
        /* Entry for the virtual destructor */
        { 0, 0, (VirtualFunctionPointer) Shape_Destructor }
    };
     
    /*
    The struct Circle maps to the Circle class in the C++ code.
    The layout of the structure is:
    - Member variables inherited from the the base class Shape.
    - Vtable pointer for the class.
    - Member variables added by the inheriting class Circle.
    */
     
    struct Circle
    {
       /* Fields inherited from Shape */
       int m_x;
       int m_y;
       VTable *pVTable;
     
       /* Fields added by Circle */
       int m_radius;
    };
     
    /*
    Function prototypes for methods in the Circle class.
    */
     
    Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius);
    void Circle_Draw(Circle *this_ptr);
    void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic);
     
    /* Vtable array for Circle */
     
    VTable VTableArrayForCircle[] =
    {
        /*
        Vtable entry virtual function Draw.
        Circle_Draw method will be invoked when Shape's
        Draw method is invoked
        */
        { 0, 0, (VirtualFunctionPointer) Circle_Draw },
     
        /*
        This vtable entry invokes the base class's
        MoveTo method.
        */
        { 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
     
        /* Entry for the virtual destructor */
        { 0, 0, (VirtualFunctionPointer) Circle_Destructor }
    };
     
    Shape *Shape_Constructor(Shape *this_ptr, int x, int y)
    {
      /* Check if memory has been allocated for struct Shape. */
      if (this_ptr == NULL)
      {
        /* Allocate memory of size Shape. */
        this_ptr = (Shape *) malloc(sizeof(Shape));
      }
     
      /*
      Once the memory has been allocated for Shape,
      initialise members of Shape.
      */
      if (this_ptr)
      {  
        /* Initialize the VTable pointer to point to shape */
        this_ptr->pVTable = VTableArrayForShape;
        this_ptr->m_x = x;
        this_ptr->m_y = y;
      }
     
      return this_ptr;
    }
     
    void Shape_Destructor(Shape *this_ptr, BOOLEAN dynamic)
    {
      /*
      Restore the VTable to that for Shape. This is
      required so that the destructor does not invoke
      a virtual function defined by a inheriting class.
      (The base class destructor is invoked after inheriting
      class actions have been completed. Thus it is not
      safe to invoke the ineriting class methods from the
      base class destructor)
      */
      this_ptr->pVTable = VTableArrayForShape;
     
      /*...*/
     
      /*
      If the memory was dynamically allocated
      for Shape, explicitly free it.
      */
      if (dynamic)
      {
        free(this_ptr);
      }
    }
     
    Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius)
    {
      /* Check if memory has been allocated for struct Circle. */
      if (this_ptr == NULL)
      {
        /* Allocate memory of size Circle. */
        this_ptr = (Circle *) malloc(sizeof(Circle));
      }
     
      /*
      Once the memory has been allocated for Circle,
      initialise members of Circle.
      */
      if (this_ptr)
      {
          /* Invoking the base class constructor */
          Shape_Constructor((Shape *)this_ptr, x, y);
    
          /* 
          Noting that here pointer is to circle rather than shape
          This overwriting the pointer set to shape in shape's constructor 
          */
          this_ptr->pVTable = VTableArrayForCircle;
     
          this_ptr->m_radius = radius;
      }
      return this_ptr;
    }
     
    void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic)
    {
      /* Restore the VTable to that for Circle */
      this_ptr->pVTable = VTableArrayForCircle;
     
      /*...*/
     
      /*
      Invoke the base class destructor after ineriting class
      destructor actions have been completed. Also note that
      that the dynamic flag is set to false so that the shape
      destructor does not free any memory.
      */
      Shape_Destructor((Shape *) this_ptr, FALSE);
     
      /*
      If the memory was dynamically allocated
      for Circle, explicitly free it.
      */
      if (dynamic)
      {
        free(this_ptr);
      }
    }
     
    void Circle_Draw(Circle *this_ptr)
    {
       glib_draw_circle(this_ptr->m_x, this_ptr->m_y, this_ptr->m_radius);
    }
     
    main()
    {   
      /*
      Dynamically allocate memory by passing NULL in this arguement.
      Also initialse members of struct pointed to by pShape.
      */
      Shape *pShape = (Shape *) Circle_Constructor(NULL, 50, 100, 25);
     
      /* Define a local variable aCircle of type struct Circle. */
      Circle aCircle;
     
      /* Initialise members of struct variable aCircle. */
      Circle_Constructor(&aCircle, 5, 5, 2);
     
      /*
      Virtual function Draw is called for the shape pointer. The compiler
      has allocated 0 offset array entry to the Draw virtual function.
      This code corresponds to "pShape->Draw();"
      */
      (pShape->pVTable[0].pFunc)(pShape);
     
      /*
      Virtual function MoveTo is called for the shape pointer. The compiler
      has allocared 1 offset array entry to the MoveTo virtual function.
      This code corresponds to "pShape->MoveTo(100, 100);"
      */
      (pShape->pVTable[1].pFunc)(pShape, 100, 100);
     
      /*
      The following code represents the Erase method. This method is
      not virtual and it is only defined in the base class. Thus
      the Shape_Erase C function is called.
      */
      Shape_Erase(pShape);
     
      /* Delete memory pointed to by pShape (explicit delete in original code).
      Since the destructor is declared virtual, the compiler has allocated
      2 offset entry to the virtual destructor
      This code corresponds to "delete pShape;".
      */
      (pShape->pVTable[2].pFunc)(pShape, TRUE);
     
      /*
      The following code corresponds to aCircle.Draw().
      Here the compiler can invoke the method directly instead of
      going through the vtable, since the type of aCircle is fully
      known. (This is very much compiler dependent. Dumb compilers will
      still invoke the method through the vtable).
      */
      Circle_Draw(&aCircle);
     
      /*
      Since memory was allocated from the stack for local struct 
      variable aCircle, it will be deallocated when aCircle goes out of scope.
      The destructor will also be invoked. Notice that dynamic flag is set to
      false so that the destructor does not try to free memory. Again, the
      compiler does not need to go through the vtable to invoke the destructor.
      */
      Circle_Destructor(&aCircle, FALSE);
    }

    参考链接:c实现原文 http://www.eventhelix.com/realtimemantra/Object_Oriented/

                  ooc原则:http://www.eventhelix.com/realtimemantra/Object_Oriented/#.UyRbuY3HkqL

    参考书籍:Object-oriented programming with ANSI-C

  • 相关阅读:
    (五)Ajax修改购物车单品数量
    (四)加入购物车和购物车操作
    flask blueprint
    2.1.2 BCD码
    2.1.1进位计数制
    1.2.3 计算机系统的层次结构
    flask的宏 macro
    计算机组成原理习题
    flask模版继承和include
    flask自定义过滤器
  • 原文地址:https://www.cnblogs.com/zhaoyl/p/3602542.html
Copyright © 2020-2023  润新知