【问题标题】:Is this a correct approach of using abstract classes with an OO approach?这是将抽象类与 OO 方法一起使用的正确方法吗?
【发布时间】:2012-05-15 08:52:04
【问题描述】:

假设我们有 2 个类 A 和 B。它们都是超类 C 的子类。现在让我们假设 C 定义了一个方法 areYouA(),这是一个询问对象是否是 A 类的对象的方法。

因此,在 c++ 中可能的代码是:

C object1 = A()

C object2 = B()

if (object1.areYouA()==true){//crazy code here regarding if it's an A object}

if (object2.areYouA()==false){//crazy code here regarding if it's a B object}

从 OO POV 中向 B 和 C 类添加方法以询问它们各自的对象是否属于 A 类是否正确???如果它不正确,那么还有什么方法可以解决这个问题????我的目标很明显,我需要 2 个 A 类和 B 类,在某些时候,我有部分二进制数据可能属于 A 类或 B 类,而且一个对象最初也属于 A 类,因为它得到完整的,它的结构需要改变,它的一些行为也需要改变,因此成为 B 类的对象。所以我的方法是将抽象类视为父类,最初声明一个 C 对象但存储一个 A 对象,然后在 B 对象更改时存储它。 有没有另一种方法,比如模式???

附加信息:

我想我不是很清楚这一点。假设我想将来自 A 对象的信息存储在 file1 中,并将来自 B 对象的信息存储在 file2 中。如果将其母类用作接口,那么我如何判断它是存储在相应文件中的 A 对象还是 B 对象?我是否应该为每个对象添加一个属性,因为它们也属于它们的文件名???这意味着如果我需要更改文件名,那么每个对象也需要更改。

【问题讨论】:

  • 您的代码无法编译,即使编译了它也不会按照您的想法进行。多态性仅通过引用和指针起作用,而不是通过副本(参见“切片”)。

标签: c++ design-patterns subclass superclass


【解决方案1】:

在我看来,这是一个设计问题,您必须更好地分析您的问题。为什么需要知道对象的类型?为什么你不在你的 A 和 B 类中实现接口方法,它可以对二进制数据做任何你需要的事情?查看访问者设计模式,了解如何以这种方式实现它。

【讨论】:

  • 访问者模式是可怕的矫枉过正,很可能在目前的情况下完全被误导了,我认为。
  • 非常感谢您指出模式以及我可能需要使用多态接口的事实。我将进一步探索我的问题,看看这是否能完全解决它。
  • @KerrekSB 这取决于问题的类型。我刚刚提到了设计模式作为一个有据可查的例子。
【解决方案2】:

正确的方法是使用虚函数来实现多态行为:

struct C
{
    virtual void do_crazy_stuff() { } // (see text below)
    virtual ~C() { }                  // always have a virtual d'tor for polymorphic bases
};

struct A : C
{
    virtual void do_crazy_stuff() { /* your crazy code for A */ }
};

struct B : C
{
    virtual void do_crazy_stuff() { /* your crazy code for B */ }
};

现在您可以在任何地方使用相同的界面:

void process_data(C & x)  // <-- Note: take argument by reference!!
{
    x.do_crazy_stuff();
}

这适用于从C派生的任何类型的对象:

int main()
{
    A x;
    B y;
    process_data(x);  // calls x.A::do_crazy_stuff
    process_data(y);  // calls x.B::do_crazy_stuff
}

如果你愿意,你甚至可以将基函数C::do_crazy_stuff 声明为纯虚函数;这使得基类抽象(所以它不能被实例化)。

【讨论】:

  • 感谢您提醒我多态性,而且我不知道我不能使用它:C object1 = A()
【解决方案3】:

首先,

C object1 = A();
C object2 = B();

对对象进行切片。它们不再是AB 类型,而是C

您可以为此使用指针:

C* object1 = new A();
C* object2 = new B();

虽然C是指针,但它们分别指向AB的实例。

其次,你的方法是错误的。似乎您没有利用多态性。如果你有在类之间共享的功能,它应该在C 中实现。如果它发生变化,你应该有virtual 方法。

关于对象类型的知识通常至少是一种代码味道。您可以简单地通过使用多态性来改变行为。虽然如果真的有必要,正确的方法是使用dynamic_cast

C* object1 = new A();
A* pA = dynamic_cast<A*>(object1);

如果object1 不指向A 类型的对象,pA 将是NULL

【讨论】:

  • 向处于学习 C++ 早期阶段的人建议使用指针和new 有点邪恶。
  • 或者,如果您建议指针和新指针,那么至少也建议一些智能指针,例如std::unique_ptrstd::shared_ptr
  • 没关系,我读了官方的c++教程,里面都是关于new和pointers的使用,虽然我需要习惯它。感谢您的考虑,非常感谢。
  • @Ale 是的,您应该接受 Nawaz 的建议,并研究智能指针。另外,请注意,如果您使用我的 sn-ps 中的原始指针,您有责任通过 delete 释放内存。
  • @Ale:确保基类的析构函数声明为virtual,无论您使用原始指针还是智能指针,这都是必需的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 2011-08-14
  • 1970-01-01
  • 2012-05-11
  • 2018-12-31
  • 2021-04-29
相关资源
最近更新 更多