Jump to content

    
Sign in to follow this  
haker_fox

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

Recommended Posts

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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this