Как инициализировать массив и передать его указатель на базовый конструктор из производного? - PullRequest
4 голосов
/ 03 февраля 2011

Переписал вопрос полностью. Пожалуйста, прочитайте внимательно

Отдельное примечание, которое не должно вас смущать: Базовый конструктор ожидает указатель на массив констант. Он не хранит указатель сам, он хранит данные!

У меня есть следующий код:

class Base {
public:
    Base(int*);
    // added this to explain why I need inheritance
    virtual void abstractMethod() = 0;
};

Base::Base(const int *array) {
    // just for example
    cout << array[0] << endl;
    cout << array[1] << endl;
    cout << array[2] << endl;
}

class Derived : private Base {
public:
    Derived();
    void abstractMethod();
};

// who will delete? how to initialize?
Derived::Derived(): Base(new int[3]) {
}

Я хочу скрыть конструктор Base (int *) от пользователя моего производного класса. Для этого мне нужно указать значения по умолчанию для этого массива.

Проблема в том, что когда я использую список инициализации, например так:

Derived::Derived(): Base(new int[3]) {
}

Массив не инициализирован, и конструктор Base выводит мусор. Еще одна проблема с этим кодом: кто освободит этот новый массив?

Как инициализировать массив перед его передачей в базовый класс? Возможно ли это вообще в C ++?

Ответы [ 6 ]

4 голосов
/ 03 февраля 2011

Краткий ответ: вы не можете (если вы не готовы полагаться на возможные причуды в конкретном компиляторе). Для соответствия стандарту Base должен быть полностью построен, прежде чем что-либо еще в Derived может быть безопасно затронуто.

Фокус вместо того, что вы пытаетесь достичь. Почему массив должен быть в Derived; почему вы чувствуете необходимость инициализировать Base? Есть, вероятно, десятки безопасных способов достижения того, что вам нужно.

1 голос
/ 03 февраля 2011

Вы можете использовать статическую функцию для генерации ваших объектов:

class Base {
public:
    Base(int*);
};

class Derived : Base {
public:
    static Derived createDerived()
    {
        int *a= new int[3];
        a[0]=a[1]=a[2]=1;
        return Derived(a);
    }
    ~Derived()
    {
       delete [] array;
    }
private:
    int *array;
    Derived(int * a):arrary(a),Base(a)
    {
    }
};
1 голос
/ 03 февраля 2011

Это действительно плохой дизайн. Зачем вам нужен конструктор, который принимает int* в вашем Base классе, когда нет члена для инициализации?
Судя по вашему комментарию к ответу Понта, кажется, вы знаете об этом недостатке.

class Base {
private:
    int array[3];
public:
    Base(int* arr);
    virtual ~Base();
};

class Derived : Base {
public:
    Derived();
};

Затем вы передадите массив обратно в базовый класс, используя списки инициализации:

Derived() : Base(new int[3]) {
    array[0] = array[1] = array[2] = 1;
}

Вы в основном вызываете конструктор class Base и передаете параметр. И конструктор Base тоже будет использовать список инициализации:

Base(int* arr) : array(arr) {
}

Также, когда конструктор Derived выполняется, объект Base уже полностью инициализирован, что обещано стандартом.
Конечно, вам придется справиться с уничтожением динамически размещенного массива в Base:

virtual ~Base(){
    delete [] array;
}

Приветствие.

0 голосов
/ 03 февраля 2011

Лучшее решение, которое я мог найти на данный момент, - это использование статического массива:

class Derived : private Base {
public:
    Derived();
    void abstractMethod();
    static int array[3];
};

int Derived::array[3] = {5, 5, 5};

Derived::Derived(): Base(array) {
}

Не стесняйтесь добавлять свои комментарии.

0 голосов
/ 03 февраля 2011

Я пришел к другому решению:

class Int3Array {
    int array[3];
public:
    Int3Array(int v1, int v2, int v3) {
        array[0] = v1;
        array[1] = v2;
        array[2] = v3;
    }
    int* getPtr() {
        return array;
    }
};

Derived::Derived(): Base((Int3Array(1,1,1)).getPtr()) {
}

Что ты думаешь? Это тоже плохо?

0 голосов
/ 03 февраля 2011

Нашли решение:

Derived::Derived(): Base(new int[3]{1,1,1}) {
}

Но, увы, это действительно только в C ++ 0x. G ++ дает мне предупреждение:

warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...