C ++ изменить тип члена в производном классе - PullRequest
3 голосов
/ 29 июня 2011

У меня есть класс Base1, который содержит массив объектов другого класса Base2.Я хотел бы иметь производный класс Derived1, который наследует все от Base1, за исключением массива типа Derived2 (который является производным классом Base2).Например, что-то вроде этого:

class Base2{
        int a2;
};

class Derived2: public Base2{
        int b2;
};

class Base1{
        Base2* list;
};

class Derived1: public Base1{
        Derived2* list;
};

Насколько я понимаю, в приведенном выше примере объект Derived1 на самом деле будет иметь ДВА массива:

list

и

Base1::list

который я не хочу.

Идея состоит в том, что все функциональные возможности Base1 все еще должны работать для объекта Derived1, поскольку Derived2 "является" Base2.Это было бы очень грязно, но я думаю, я мог бы просто удалить [] массив Base1 :: list в конструкторе Derived1.

Кто-нибудь видит решение этой проблемы?Кажется, что-то такое случается часто, и я не могу поверить, что простого решения не существует.Будет ли работать шаблоны?Я думал, что нет, поскольку все функции в Base1 и Derived1 должны знать, что они имеют дело с объектами Base2 и Derived2, соответственно.

Ответы [ 4 ]

2 голосов
/ 29 июня 2011

То, что вы пытаетесь сделать, в общем случае кажется опасным, но я предполагаю, что вы знаете риски;)

Я могу предложить два решения:

Вариант 1:

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

class Base1 {
    protected:
    void *ptr
    public:
    Base2 *list() {return (Base2*)ptr;}
};

class Derived1 : public Base1 {
    public:
    Derived2 *list() {return (Derived2*)ptr;}
};

По сути, Base2::list будет скрыт Derived2::list,Обратите внимание, вы не можете сделать их виртуальными и извлечь выгоду из виртуальности.Тип возвращаемого значения должен быть известен во время компиляции.

Опция 2:

Вы можете использовать шаблонный базовый класс.

template <typename T>
class List {
    public:
    T *list
    //implement all functionality which is common, regardless of the type T
};

class Base1 : public List<Base2> {
    //specifics for Base2 type
};

class Derived1 : public List<Derived2> {
    //specifics for Derived2
};

Примечаниечто в этой конструкции Base1 и Derived1 не связаны напрямую, а вместо этого имеют общего предка.

2 голосов
/ 29 июня 2011

Что вы ожидаете, когда кто-то понизит класс Derived1 до Base1?Сбой при использовании list после саботажа базового класса.Лучше всего продолжать использовать базовый класс list и убедиться, что в список включены только объекты типа Derived2.Если содержимое списка не может быть изменено извне, это будет работать и безопасно.

Да, я знаю, что еще можно сказать об этом, но давайте сделаем это один шаг за раз.

1 голос
/ 29 июня 2011

Не думаю, что существует что-то простое, что решает вашу проблему.

Я бы использовал один из следующих способов -

ВАРИАНТ 1 Скройте список Base2 * (в классе base1), сделав его закрытым, и сохраните его, наследуя производный класс (output1). И, конечно, определите функцию получения в классе base1 для доступа к списку.

ВАРИАНТ 2 Просто измените тип списка в классе base1 на (указатель на) Derived2 и полагайтесь на тот факт, что указатель на производный класс совместим по типу с указателем на его базовый класс.

ВАРИАНТ 3 Забудьте о наследовании и используйте шаблоны. Вам просто нужно будет указать тип (Base2 * или Derived2 *) при создании объекта, и жизнь снова станет прекрасной.

1 голос
/ 29 июня 2011

Я бы удалил массив Base2 из Base1 и создал бы новый класс со списком:

class Base2{
        int a2;
};

class Derived2: public Base2{
        int b2;
};

class Base1{
};

class Base1WithList : public Base1{
        Base2* list;
};

class Derived1: public Base1{
        Derived2* list;
};
...