Jump to content

    

Есть ли возможность в наследованном классе изменить содержимое массива родительского класса

35 минут назад, haker_fox сказал:

Не совсем. Нужна подмена. Т.е. массив должен быть один в итоге.

А как же с ним будут работать функции базового класса? Которые в дочерних классах не перегружены.

Я понял что Вам нужно такое:

Спойлер

class Base1 {
  static void * const arr_b[2];
  public:
  Base1() {};
  virtual void * const * Arr() const { return arr_b; }
};
class Child1 : public Base1 {
  static void * const arr_c[2];
  public:
  Child1() : Base1() {};
  virtual void * const * Arr() const { return arr_c; }
};
class Child2 : public Base1 {
  static void * const arr_c[2];
  public:
  Child2() : Base1() {};
  virtual void * const * Arr() const { return arr_c; }
};
void * const Base1::arr_b[2] = {(void *)1, (void *)2};
void * const Child1::arr_c[2] = {(void *)11, (void *)12};
void * const Child2::arr_c[2] = {(void *)21, (void *)22};
Child1 const m1;
Child2 const m2;

 

Использование:

static int DteZZZ(char const *str, uint, uint)
{
  Base1 const *p = &m1;
  if (*str == '1') p = &m2;
  LogCR("child's content = %u, %u", (p->Arr())[0], (p->Arr())[1]);
  return DteRes_OK;
}

Результат работы (по false): child's content = 11, 12

Результат работы (по true): child's content = 21, 22

 

PS: Массив - уникальный для каждого из дочерних классов. И в единственном экземпляре.

Share this post


Link to post
Share on other sites
Quote

Но! Задача решена хоть и через классы, но по-сути используя сишные указатели...

Так замените тип. А массив и указатель - это одно и то же. От этого в рамках C++ не уйти. Вопрос в том, что если размер члена класса заранее неизвестен, то данный код не соберётся, поскольку невозможно создать экземпляр класса. И все размеры должны быть известны на момент инстанциирования.

Share this post


Link to post
Share on other sites
1 minute ago, one_eight_seven said:

type * m_array[] -- это, на самом деле type* m_array[0];

Вы сообщение моё точно внимательно прочитали? Я, кажется, упомянул там, что это псевдокод. Тогда уж и это недопустимо

m_array.add(UartDrv);    // для управления вентилятором нам нужен драйвер последовательного порта
    m_array.add(FanDrv);     // а ещё драйвер самого вентилятора
    m_array.add(KeyboardDrv);// ну и драйвер клавиатуры

Какой массив это позволит себе? Ещё раз, я хочу что-то типа ТАКОГО подхода.

3 minutes ago, one_eight_seven said:

Компилятор не будет рассчитывать

А кто? Линкер?

1 minute ago, one_eight_seven said:

И все размеры должны быть известны на момент инстанциирования.

Да кто с этим спорит-то? Речь идёт о метапрограммировании, с использованием рюшечек Си++14, 17. Посмотрите-же ссылку с хабры.

Share this post


Link to post
Share on other sites
5 minutes ago, haker_fox said:

Да кто с этим спорит-то? Речь идёт о метапрограммировании, с использованием рюшечек Си++14, 17. Посмотрите-же ссылку с хабры.

Если взять ссылку с хабры, то там, буквально разворот того, что у меня свёрнуто в цикл, никто не мешает его развернуть и сделать индивидуальные присваивания (более того, скорее всего у вас так и было бы). И вы поймите, то, что я показываю - это тоже псевдокод. Просто тип данных выбран - инт, и способ объединить инт - массив.

Собственно, что бы вы не использовали, для вызова одинакового метода всех экзепляров в массиве/списке/кортеже, будет одно и то же - итеративный проход по этой структуре данных и вызов требуемого вам метода, либо без использования итератора - прямое обращение к элементам структуры данных, если это возможно (в случае списка - это невозможно).

А "красиво" - это прилагательное. Для каждого оно своё.

Share this post


Link to post
Share on other sites

2 ТС - то, что вы хотите наверное можно сделать через variadic templates и constexpr. И указатели на объекты, которые вы хотите сложить в массив, должны быть top level символами в исходнике.

Но это будет та ещё жесть :crazy:

Share this post


Link to post
Share on other sites
3 hours ago, xvr said:

Но это будет та ещё жесть

Угу, как в примере с хабры)))))))))))))))

3 hours ago, xvr said:

variadic templates и constexpr.

Да да, совершенно верно. Но я не могу это сделать сам. Похоже, придётся ограничится связным списком...

Share this post


Link to post
Share on other sites
2 минуты назад, haker_fox сказал:

Да да, совершенно верно. Но я не могу это сделать сам. Похоже, придётся ограничится связным списком...

А чем мой вариант не подошёл?

Share this post


Link to post
Share on other sites
9 minutes ago, haker_fox said:

Да да, совершенно верно. Но я не могу это сделать сам. Похоже, придётся ограничится связным списком... 

Вы понимаете, что сложность доступа к драйверу будет в случае списка O(N) вместо O(1) в случае массива? А плюсы списка - динамическая сущность и удобство переупорядочивания вы не будете использовать? Или вам это и не нужно?

Edited by one_eight_seven

Share this post


Link to post
Share on other sites
15 minutes ago, jcxz said:

А чем мой вариант не подошёл?

Мне нравится ваш вариант, но смущает то, что размерность массива задаётся вручную( Может быть я ошибаюсь, я ещё не компилировал ваш код...

11 minutes ago, one_eight_seven said:

Вы понимаете, что сложность доступа к драйверу будет в случае списка O(N) вместо O(1) в случае массива?

Понимаю, но упустил( Хотя это не критично.

13 minutes ago, one_eight_seven said:

Или вам это и не нужно?

Нет, не нужно. Он ведь в ПЗУ лежать будет.

Share this post


Link to post
Share on other sites
4 minutes ago, haker_fox said:

Нет, не нужно. Он ведь в ПЗУ лежать будет.

Тогда тем более непонятно, что даёт список. Никакой же пользы, кроме вреда.

P.S. Если вы не хотите в явной форме задавать размер массива, а хотите, чтобы он определялся автоматически, то есть такая вещь, как нуль-терминированный массив.

Edited by one_eight_seven

Share this post


Link to post
Share on other sites
27 minutes ago, one_eight_seven said:

нуль-терминированный массив.

Это что? У меня гугл кроме строк ничего полезного не ищет( Если можно, то дайте ссылочку на материал.

Share this post


Link to post
Share on other sites
1 час назад, haker_fox сказал:

Мне нравится ваш вариант, но смущает то, что размерность массива задаётся вручную( Может быть я ошибаюсь, я ещё не компилировал ваш код...

Так в моём варианте - для каждого Child класса есть свой массив. Со своим размером для каждого из ChildX. Если нужно получать размер массива через указатель на базовый класс - следует создать ещё одну виртуальную член-функцию (аналогичную Arr()), которую перегрузить в каждом из ChildX. И каждый будет возвращать свой размер.

Для каждого ChildX это будет функция типа: virtual int ArrN() const { return sizeof(arr_c) / sizeof(arr_c[0]); }

Хотите другой массив - создаёте новый ChildX со своим массивом который имеет свой размер.

Всё.

Share this post


Link to post
Share on other sites
1 hour ago, haker_fox said:

Это что? У меня гугл кроме строк ничего полезного не ищет( Если можно, то дайте ссылочку на материал. 

Spoiler

#include <iostream>
#include <string>

using namespace std;

class Element {
    public:
        Element(string name): name(name) {}
        void open () {
            cout << "Opening " << name << endl;
        }
    private:
        string name;
        Element() {}
};

class Base {
    public:
        void open_all_drivers() {
            size_t size = get_size();
            for (size_t i = 0; i < size; ++i) {
                get_element(i).open();
            }
        }
    private:
        virtual size_t get_size() = 0;
        virtual Element & get_element(size_t idx) = 0;
};

class Derived : public Base {
    public:
        Derived(){
            /* Here we do use NULL-terminated array to calculate size */
            elements_qty = 0;
            while (elements[elements_qty]) { // While element point to something
                ++elements_qty; // we increment counter
            }
        }
    private:
        static Element * elements [];
        virtual size_t get_size() final {
            return elements_qty;
        }
        virtual Element & get_element(size_t idx) {
            return *elements[idx];
        }
        size_t elements_qty;
};

Element led_driver("led_driver");
Element port_a_bit_3_driver("port_a_bit_3_driver");

/* NULL - terminated array */
Element * Derived::elements [] = {
    &led_driver,
    &port_a_bit_3_driver,
    nullptr,
};

Derived tst;

int main () {
    Base * p = &tst;
    p->open_all_drivers();
    return 0;
}

 

 

35 minutes ago, jcxz said:

Для каждого ChildX это будет функция типа: virtual int ArrN() const { return sizeof(arr_c) / sizeof(arr_c[0]); }

В с++17, кстати, это можно сделать с помощью std::size().

Share this post


Link to post
Share on other sites

@one_eight_seven, ого, ну и пример у вас)) Но суть понял. Тут, главное, nullptr в конце не забыть. Т.е. автоматизация неполная. Но вчера вечером посидев с вариативными шаблонами и конструкторами, пришёл к выводу, что красивого способа нет. Либо нужно написать что-то жуткое(

 

9 hours ago, jcxz said:

Хотите другой массив - создаёте новый ChildX со своим массивом который имеет свой размер.

Да, действительно! Я разобрался с вашим примером! Спасибо!

 

Теперь буду думать, и что-то выбирать)

Share this post


Link to post
Share on other sites
9 hours ago, haker_fox said:

Т.е. автоматизация неполная

Here you go:

Spoiler

#include <iostream>
#include <string>
#include <map>

typedef enum {
    LED_DRIVER,
    PORT_A_BIT_3_DRIVER,
} DriverIndex_e;

using namespace std;

class Element {
    public:
        Element(string name): name(name) {}
        void open () {
            cout << "Opening " << name << endl;
        }
        void introduce() {
            cout << "My name is " << name << endl;
        }
    private:
        string name;
        Element() {}
};

class Base {
    public:
        void open_all_drivers() {
            map <size_t, Element &>& my_map = get_elements();
            for (auto& x : my_map) {
                x.second.open();
            }
        }
        void access(size_t id) {
            get_elements().at(id).introduce();
        }
    private:
        virtual map <size_t, Element &> & get_elements() = 0;
};

class Derived : public Base {
    private:
        static map <size_t, Element &> elements;
        virtual map <size_t, Element &> & get_elements() final {
            return elements;
        }
};

Element led_driver("led_driver");
Element port_a_bit_3_driver("port_a_bit_3_driver");

map <size_t, Element &> Derived::elements = {
    {LED_DRIVER, led_driver},
    {PORT_A_BIT_3_DRIVER, port_a_bit_3_driver},
};

Derived tst;

int main () {
    Base * p = &tst;
    p->open_all_drivers();
    p->access(PORT_A_BIT_3_DRIVER);
    return 0;
}

 

Если вам не нужен произвольный доступ (метод access в базовом классе в примере), то можно использовать std::set, вместо std::map, тем более, я не интересовался насколько быстрым будет этот самый произвольный доступ.

P.S. И без указателей, которые тут почему-то не любят, что странно, ведь "под капотом" у всех этих контейнеров - всё-равно указатели.

Spoiler

[avi@dev tst]$ g++ -std=gnu++17 tst1.cpp -o bin/tst1.out
[avi@dev tst]$ bin/tst1.out 
Opening led_driver
Opening port_a_bit_3_driver
My name is port_a_bit_3_driver

 

 

Edited by one_eight_seven

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now