【问题标题】:Can an abstract class be member of other concrete class as composition relationship ? c++抽象类可以作为组合关系成为其他具体类的成员吗? C++
【发布时间】:2012-04-04 15:21:28
【问题描述】:

P 是一个抽象类,我想让它成为 A 类的成员,A 类是一个普通的具体类。如果是的话,有可能吗?关系是组合 感谢您的帮助

【问题讨论】:

  • 你能把它作为私有继承吗?
  • 为什么不自己试试呢?
  • @peter:怎么样?鉴于编译器错误和未定义的行为,几乎没有什么可以从“尝试”中学到。

标签: c++ class abstract-class composition


【解决方案1】:

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

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

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

class concrete
{
    abstract obj;

};
int main()
{
    return 0;
}

编译:

prog.cpp:8:错误:不能将字段“concrete::obj”声明为抽象类型“abstract”
prog.cpp:2:注意:因为以下虚函数在“抽象”中是纯函数:
prog.cpp:3: 注意:virtual void abstract::something()

Compilable sample:

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

class concrete
{
    abstract *ptr;

};
int main()
{
    return 0;
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案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);
      

      【讨论】:

        【解决方案4】:

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

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

        如果您可以访问这本书,请参阅第 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;
        }
        

        【讨论】:

          【解决方案5】:

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

          不对称很明显,因为可以使用抽象类作为基础,甚至对象的基础子对象也必须实例化;但在这种情况下,该操作是允许的,只是生成的类会自动变为抽象类。

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-01-08
            • 1970-01-01
            • 1970-01-01
            • 2011-02-11
            • 2019-06-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多