抽象类可以作为组合关系的其他具体类的成员吗? C ++

时间:2012-03-20 06:04:06

标签: c++ class abstract-class composition

P是一个抽象类,我想让它成为A类的成员,这是一个普通的具体类。有可能,如果是的话。关系是构成 谢谢你的帮助

5 个答案:

答案 0 :(得分:5)

由于P是抽象的,因此您永远无法创建该类型的对象。但是,您可以将P的指针存储为类A的成员;然后,这个指针成员可以指向P的(具体)子类的实例。

答案 1 :(得分:3)

没有。组合关系意味着类Client实际上包含AbstractClass类型的成员变量。

我假设您对“抽象类”的定义是具有至少一个纯虚函数的类的常见类。这意味着它不能成为具体类的成员,因为该类无法实例化。

您可以拥有一个抽象类的引用或指针,包括一个为您管理生命周期的类,例如:

   class Client {
    public:
      Client(AbstractClass* adopted) : ownedAbstract(adopted) {}
    ...
    std::shared_ptr<AbstractClass> ownedAbstract;

   };

   class AbstractClass{
    public:
      virtual ~AbstractClass()=0;  // virtual dtor needed so can delete AbstractClass*    
   };       

   class AbstractSubclass : public AbstractClass{
    public:
      virtual ~AbstractSubclass();
   };


   Client fred(new AbstractSubclass);

答案 2 :(得分:2)

您无法创建抽象类的任何对象。所以你不能这样做。
但是,您可以拥有一个类成员,它是指向抽象类的指针。

Here 是一个代码示例,用于证明:

class abstract
{
   virtual void somethiing() = 0;
};

class concrete
{
    abstract obj;

};
int main()
{
    return 0;
}

编译:

  

prog.cpp:8:错误:无法将字段'concrete :: obj'声明为抽象类型'abstract'
  prog.cpp:2:注意:因为以下虚函数在'abstract'中是纯粹的:
  prog.cpp:3:注意:virtual void abstract :: somethiing()

<强> Compilable sample:

class abstract
{
   virtual void somethiing() = 0;
};

class concrete
{
    abstract *ptr;

};
int main()
{
    return 0;
}

答案 3 :(得分:0)

您可能无法在另一个类中显式实例化抽象类。但是你可以给一个抽象基类的纯虚函数一个定义,这个定义又可以在派生类中调用,感觉很像组合。

有效的C ++编程(第二版)表明抽象类中的纯虚函数可以具有主体(定义)的原因是因为继承类可以提供在其体内调用纯虚拟版本的函数的实现。

如果您有权访问该书,请参阅第36项。

这是我拼凑在一起的一个例子。它演示了如何通过从抽象类继承接口并使用其实现来组成派生类中函数定义的实现来实现对象组合的形式。

#include <iostream>

class P {
  public:
    virtual void say_hello() = 0;
};

void P::say_hello() { std::cout << "Hello world!" << std::endl; }

class A :public P {
  public:
    void say_hello() { P::say_hello(); }
};

int main() {
    A x;
    x.say_hello();
    return 0;
}

结果将是A类的'say_hello'将以相同的名称调用P的纯虚拟版本的函数。因此,调用A的“say_hello()”将最终打印出“Hello world。”

抽象类中的公共和受保护成员数据也可用于派生类。

#include <iostream>
#include <string>

using namespace std;

class P {
  public:
    P() { audience = "world"; }
    virtual void say_hello() = 0;
  protected:
    string audience;
};

void P::say_hello() { cout << "Hello " << audience << "!" << endl; }

class A :public P {
  public:
    void say_hello() { P::say_hello(); }
    void say_goodbye() { cout << "Goodbye " << audience << "." << endl; }

};

int main() {
    A x;
    x.say_hello();
    x.say_goodbye();
    return 0;
}

答案 4 :(得分:0)

我理解这听起来不对称,但答案是否定的。抽象类无法实例化,因此不能用作另一个类的成员。

不对称是显而易见的,因为您可以使用抽象类作为基础,甚至必须实例化对象的基础子对象;但在这种情况下,操作是允许的,只是结果类自动变为抽象。

然而,逻辑上的原因是,在最后一种情况下,您将能够从这个新的抽象类派生出一个具体的类,而在前一种情况下,C ++语言语法无法替代包含的对象类型使用从该类型派生的类的对象。

在某种意义上,类的/ a基础子对象的类型可以稍后在继承层次结构中进行修改,而常规成员子对象的类型是固定的。

当然,您可以在对象中使用指针或对抽象类的引用,因为在这种情况下,对象的实际类型将是具体的,并且仅在运行时才会知道。