代码之家  ›  专栏  ›  技术社区  ›  seanmcl

C语言中的数据抽象和二进制方法++

  •  2
  • seanmcl  · 技术社区  · 11 年前

    我是C++的新手,正在努力理解数据抽象与二进制方法(如等式)的结合。我想定义一个接口

    class A {
     public:
      static A* Make(int);
      virtual ~A() {};
      virtual bool Eq(A*) = 0;
    };
    

    使用工厂模式,我可以隐藏实现:

    class B : public A {
     public:
      B(int x) : x_(x) {}
    
      bool Eq(A* a) {
        return x_ == dynamic_cast<B*>(a)->x_;
      }
    
     private:
      int x_;
    };
    
    A* A::Make(int x) {
      return new B(x);
    }
    

    然后我可以使用抽象:

    A* a = A::Make(1);
    A* b = A::Make(2);
    
    if (a->Eq(b)) {
      cout << "Yes!" << endl;
    } else {
      cout << "No!" << endl;
    }
    

    然而,由于各种原因,动态演员阵容很糟糕。在我看来,最大的问题是可以用C将A子类化,然后将C类型的对象传递给A->Eq,这将导致未定义的行为。我不知道如何定义一个二进制方法,以便代码可以访问这两个对象的私有成员。我的直觉是,这可以使用访问者模式来完成,但我没能想出解决方案。

    对于那些了解ML的人,我主要想做以下几点:

    module A : sig
      type t
      val make: int -> t
      val eq: t -> t -> bool
    end = struct
      type t = int
      let make x = x
      let eq x y = (x = y)
    end
    
    4 回复  |  直到 11 年前
        1
  •  2
  •   Thomas Matthews    11 年前

    您不希望使相等函数成为虚拟函数。

    下面是一个例子:

    class Animal
    {
      public:
        virtual bool is_equal(const Animal * p_a) = 0;
    };
    
    class Human : public Animal
    {
      public:
        bool is_equal(const Animal * p_a);
    };
    
    class Toad : public Animal
    {
      public:
        bool is_equal(const Animal * p_a);
    };
    

    如果我创建两个指向Animals的指针变量:

       Animal * p_animal_human = new Human;
       Animal * p_animal_toad  = new Toad;
    

    虚拟的 is_equal 方法允许我比较两类动物:

       if (p_animal_human->is_equal(p_animal_toad)
    

    这可能会导致一大堆运行时错误,在本例中,您不想将 Human 等于 Toad 你可能想比较两个 人类 一两个实例 蟾蜍 实例。

    在上面 if 语句,只有 Animal 对两个类共有的数据进行比较。

    在StackOverflow中搜索术语“[C++]切片”。

        2
  •  1
  •   JRG    11 年前

    在我的评论的基础上,您可以使用PIMPL(指向实现的指针)习惯用法编写代码,如下所示:

    在头文件(a.hpp)中

    class A
    {
    public:
       A(int);
       ~A();
       bool Eq(const A& a) const;
    
    private:
       class AImpl;
       AImpl* implementation_;
    };
    

    在实现文件(a.cpp)中

    struct A::AImpl {
       AImpl(int x) : x_(x) {}
       int x_;
    };
    
    A::A(int x)
       : implementation_(new AImpl(x))
    {}
    
    A::~A()
    {
       delete implementation_;
    }
    
    bool
    A::Eq(const A& rhs) const
    {
       return implementation_->x_ == rhs.implementation_->x_;
    }
    

    在您的主文件中

    #include "a.hpp"
    
    int main()
    {
       A one(1);
       A two(2);
    
       return one.Eq(two);
    }
    

    因为所有实际的代码都在实现文件中,所以你无法从其他类中看到它(只包括头文件a.hpp)。为了清楚起见,我使用了一个原始指针,但在实际设置中,你需要使用一个合适的智能指针。

        3
  •  0
  •   Jarod42    11 年前

    您可以使用以下内容:

    class A {
    public:
        virtual ~A() {};
        virtual bool Eq(const A& a) const = 0;
    };
    
    class B : public A {
    public:
        explicit B(int x) : x_(x) {}
    
        virtual bool Eq(const A& a) const {
            const B* b = dynamic_cast<const B*>(&a);
            return b != NULL && Eq(*b);
        }
        bool Eq(const B& rhs) const { return x_ == rhs.x_; }
    
    private:
        int x_;
    };
    
    class C : public A {
    public:
        explicit C(int x) : x_(x) {}
    
        bool Eq(const A& a) const {
            const C* c = dynamic_cast<const C*>(&a);
            return c != NULL && Eq(*c);
        }
        bool Eq(const C& rhs) const { return x_ == rhs.x_; }
    
    private:
        int x_;
    };
    
    int main() {
        B b1(42);
        B b2(42);
        C c(42);
        A& ab1 = b1;
        A& ab2 = b2;
        A& ac = c;
    
        std::cout << "ab1.Eq(ab2) = " << ab1.Eq(ab2) << std::endl; // true
        std::cout << "ab1.Eq(ac) = " << ab1.Eq(ac) << std::endl;   // false
    
        return 0;
    }
    
        4
  •  0
  •   Juniar    11 年前
    • “我不知道如何定义一个二进制方法,以便代码可以访问两个对象的私有成员”
    • 在C++中,您可以使用关键字friend从其他类或对象类型访问私有成员函数和受保护成员函数。
    • 您需要在头文件中包含包含私有成员函数或受保护成员函数的类,例如;
    • A类{
    • 朋友B类;
    • }
    • 你也可以反过来做。因此,B类可以是a类的朋友,而a类可以是B类的朋友。