Создание экземпляров производных объектов из базового класса

#c #inheritance

#c #наследование

Вопрос:

Пытаюсь создать класс типа драйвера, где, ниже, Base — это драйвер, которому передается тип при создании экземпляра. Тип, в данном случае 2, используется для создания правильного производного объекта.

Мой компилятор выдает синтаксическую ошибку объявления в строке «Базовый класс».

Моя конечная цель — иметь возможность делать это:

 Base *B;

    B = new Base(2);
    if(B)
    {
      B->DoStuff();
      B->DoMoreStuff();
      delete B;
    }
  

Вот мой код, который не будет компилироваться…

 class Base
{
public:

    Base(int h);
    virtual ~Base();

private:
    int hType;
    Base *hHandle;
};


class Derived1 : public Base
{
public:
    Derived1();
    virtual ~Derived1();

};

class Derived2 : public Base
{
public:
    Derived2();
    virtual ~Derived2();

};

Base::Base(int h)
{
    hType = h;

    switch(h)
    {
        case 1:
            hHandle = new Derived1;
        break;

        case 2:
            hHandle = new Derived2;
        break;

    }
}


Derived1::Derived1():Base(1)
{
    printf("nDerived1 Initializednn");
}

Derived2::Derived2():Base(2)
{
    printf("nDerived2 Initializednn");
}
  

Ниже приведен обновленный код, показывающий полный исходный код. Думаю, теперь я понимаю, почему он не будет компилироваться. Как указано ниже, у меня есть бесконечный цикл вызовов ‘new’

 #include <stdio.h>

class Base
{
public:

    Base();
    Base(int h);
    Create (int h);
    virtual ~Base();

private:
    int hType;
    Base *hHandle;
};


class Derived1 : public Base
{
public:
    Derived1();
    virtual ~Derived1();

};

class Derived2 : public Base
{
public:
    Derived2();
    virtual ~Derived2();

};

Base::Base()
{

}

Base::Base(int h)
{
    Create(h);
}

Base::Create(int h)
{
    hType = h;

    switch(h)
    {
        case 1:
            hHandle = new Derived1;
        break;

        case 2:
            hHandle = new Derived2;
        break;

    }
}

Derived1::Derived1()
{
    printf("nDerived1 Initializednn");
}

Derived2::Derived2()
{
    printf("nDerived2 Initializednn");
}
  

Комментарии:

1. Каков текст ошибки? Если это ссылается на первую строку вашего фрагмента кода, это не выглядит неправильно.

2. Что насчет среды выполнения? Когда вы создаете Base(1), конструктор создает новый производный, который вызывает его базовый класс, Base(1), который создает новый производный, который вызывает его базовый класс …

3. @Eric: пожалуйста, используйте либо std::unique_ptr , boost::scoped_ptr либо std::auto_ptr (последнее хуже). У вас утечка памяти в вашем игрушечном примере :/

4. @Matthieu M: Спасибо за ваш вклад, но мне это не помогает. boost и стандартный шаблон использовать нельзя. Код, скорее всего, будет перенесен на встроенную платформу, где они не существуют. В частности, можете ли вы указать на утечку памяти?

5. @Бо Перссон: Хорошо, думаю, я понял. Когда во время выполнения (предполагая, что я смогу туда попасть), когда я создаю новую базу, вызывается new Derived, что требует повторного вызова new Base снова и так далее и тому подобное… понял. Это помогает.

Ответ №1:

Похоже, вы пытаетесь создать фабрику классов.

Я бы рекомендовал вам использовать статический метод в Base, который возвращает либо Derived1, либо Derived2.

 class Base
{
public:
    static Base* Create(int);
    virtual void DoStuff() = 0;
}

class Derived1 : public Base
{
    Derived1()
    {
        printf("nDerived1 Initializednn");
    }

    virtual void DoStuff()
    {
    }   
}

class Derived2 : public Base
{
    Derived2()
    {
        printf("nDerived2 Initializednn");
    }

    virtual void DoStuff()
    {
    }   
}

Base* Base::Create(int n)
{
    if (n==1)
        return new Derived1();
    else if (n==2)
        return new Derived2();
    else
        return nullptr;
}

void main()
{
    Base* B = Base::Create(2);
    if(B)
    {
        B->DoStuff();
        delete B;
    }
}
  

Комментарии:

1. это интересно, я могу прочитать / понять это, но я все еще ломаю голову над тем, почему мой код не компилируется? В конечном счете, это не отвечает на мой вопрос. Я не хочу, чтобы вызывающий должен был знать подробности Base::Create. Я хочу, чтобы вызывающий просто вызывал new Base (тип), если это возможно?

2. Во-первых, ваш код пытается вызвать функции, которые у него не объявлены, вам пришлось бы создавать прокси-методы, которые вызывают их аналоги в hHandle. Во-вторых, и это самое главное, компилятор не поймает, что создание Derived1 вызовет базовый конструктор для создания другого экземпляра Derived1 в бесконечном цикле.

3. Игнорируйте первую часть этого последнего комментария… Если класс Base имеет синтаксическую ошибку, это, вероятно, из-за отсутствия точки с запятой над ним, возможно, во включаемом файле. Я не вижу ничего плохого в этой строке. Можете ли вы предоставить компилятору полную ошибку?

4. Я не понимаю, как код пытается вызвать функции, которые у него не объявлены? Первая функция, реализация, Base::Base, теперь касается Derived1 и Derived2, правильно? Если нет, не исправит ли это прямое объявление Derived1 и Derived2? Я пробовал это, между прочим, и это не сработало. То, что вы видите выше, является полным исходным кодом. Единственное, чего не хватает, это #include <stdio.h> и file1.cpp файл, который реализует функцию int main() для тестирования.

5. Причина использования наследования заключается в возможности повторного использования кода в базовом классе. Попытка сделать ваш базовый класс фабрикой классов означает, что базовый класс несет более одной ответственности, что нарушает важный принцип проектирования (единая ответственность). Кроме того, если вы когда-либо добавите Derived3, вам придется коснуться кода в Base, что нарушает другой принцип проектирования (Открытый / закрытый).