Может ли абстрактный класс быть членом другого конкретного класса как композиционные отношения? C ++ - PullRequest
5 голосов
/ 20 марта 2012

P - абстрактный класс, я хочу сделать его членом класса A, который является нормальным конкретным классом. Возможно ли, если да, то как. Отношения это композиция Спасибо за помощь

Ответы [ 5 ]

5 голосов
/ 20 марта 2012

Поскольку P является абстрактным, вы никогда не сможете создать объект этого типа.Однако вы можете хранить указатель на P как член класса A;этот член-указатель может затем указывать на экземпляр (конкретного) подкласса P.

3 голосов
/ 20 марта 2012

Нет. Композиционные отношения подразумевают, что класс 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 голосов
/ 20 марта 2012

Вы не можете создавать объекты абстрактного класса.поэтому вы не можете сделать это.
Однако у вас может быть член класса, который указывает на абстрактный класс.

Здесь - это пример кода, чтобы доказать этоto:

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

class concrete
{
    abstract obj;

};
int main()
{
    return 0;
}

Компиляция:

prog.cpp: 8: ошибка: невозможно объявить поле 'concrete :: obj' как абстрактный тип'abstract'
prog.cpp: 2: note: потому что следующие виртуальные функции являются чистыми внутри 'abstract':
prog.cpp: 3: note: virtual void abstract :: somethiing ()

Составной образец:

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

class concrete
{
    abstract *ptr;

};
int main()
{
    return 0;
}
0 голосов
/ 20 марта 2012

Я понимаю, это звучит асимметрично, но ответ - нет.Абстрактный класс не может быть создан и поэтому не может использоваться как член другого класса.

Асимметрия очевидна, поскольку вы можете использовать абстрактный класс в качестве базового, и даже базовый подобъект объекта должен быть создан;но в этом случае операция разрешена и просто результирующий класс автоматически становится абстрактным.

Однако логическая причина в том, что в этом последнем случае вы сможете извлечь из этого нового абстрактного класса конкретный класс, в то время как вВ первом случае с синтаксисом языка C ++ невозможно было бы впоследствии заменить включенный тип объекта объектом класса, производным от этого типа.

В некотором смысле тип базового подобъекта / a объектакласс может быть впоследствии изменен вниз в иерархии наследования, в то время как тип подобъекта обычного члена фиксирован.

Конечно, вы можете использовать указатель или ссылку на абстрактный класс в объекте, потому что в этом случаереальный тип объекта будет конкретным и будет известен только во время выполнения.

0 голосов
/ 20 марта 2012

Вы не можете явно создавать абстрактный класс внутри другого класса. Но вы можете дать чисто виртуальным функциям абстрактного базового класса определение, которое, в свою очередь, может быть вызвано в производном классе таким образом, который во многом напоминает композицию.

Эффективное программирование на 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;
}

Результатом будет то, что 'say_hello' класса A будет вызывать чисто виртуальную версию функции P с тем же именем. Поэтому вызов «say_hello ()» для A приведет к выводу «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;
}
...