2

我是 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

4 回答 4

2

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

这是一个例子:

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

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

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

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

   if (p_animal_human->is_equal(p_animal_toad)

这可能会导致一大堆运行时错误,并且在本例中,您不想比较 aHuman等于 a Toad。您可能想要比较两个Human实例或两个Toad实例。

在上面的if陈述中,只Animal比较了两个类共有的数据。

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

于 2013-08-31T17:31:55.187 回答
1

扩展我的评论,您可以使用 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)中看到它。为清楚起见,我使用了原始指针,但在实际设置中,您可能希望使用适当的智能指针。

于 2013-08-31T17:40:39.633 回答
0

你可以使用类似的东西:

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;
}
于 2013-08-31T17:37:31.203 回答
0
  • “我不知道如何定义二进制方法,以便代码可以访问两个对象的私有成员”
  • 在 C++ 中,您可以使用关键字friend 从另一个类或对象类型访问私有成员函数和受保护成员函数。
  • 您需要在头文件中包含包含私有成员函数或受保护成员函数的类,例如;
  • A类{
  • B类朋友;
  • }
  • 你也可以反过来做。因此 B 类可以是 A 类的朋友,A 类可以是 B 类的朋友。
于 2013-08-31T22:21:23.950 回答