Форум программистов, компьютерный форум, киберфорум
ООП и паттерны
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 10.10.2016
Сообщений: 2

Добавление свойств в базовый класс

10.10.2016, 07:49. Показов 882. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Товарищи, подскажите, как в приличном обществе принято решать такую задачу:

Имеем, например, такую иерархию классов
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class A_Base
{
  int x;
  int y;
  
  public A_Base(int x, int y) 
  { 
    this.x = x;
    this.y = y;
  }
}
 
class A_First : A_Base
{
  string name;
  
  public A_First(int x, int y, string name):base(x,y) 
  { 
    this.name = name; 
  }
}
 
class A_Second : A_First
{
  string surname;
  
  public A_Second(int x, int y, string name, string surname):base(x,y,name)
  {
    this.surname = surname;
  }
}
Теперь нам понадобилось в A_Base добавить ещё одно свойство (и соответственно, инициализировать его в конструкторе)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
class A_Base
{
  int x;
  int y;
  int z;
  
  public A_Base(int x, int y, int z) 
  { 
    this.x = x;
    this.y = y;
    this.z = z;
  }
}
Значит придется во всей иерархии классов менять определение конструктора, дописывая туда новый параметр z, хотя сами эти конструкторы мы не меняем - меняем только вызов родителя. И как-то это не очень хорошо.
C#
1
2
3
4
5
6
7
8
9
class A_First : A_Base
{
  string name;
  
  public A_First(int x, int y, int z, string name):base(x,y,z) 
  { 
    this.name = name; 
  }
}
Как у продвинутых ООП-товарищей принято поступать в подобных случаях?
Заводить отдельный класс/структуру, которая будет параметром для конструктора?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A_Init
{
  int x;
  int y;
  int z;
}
 
class A_Base
{
  int x;
  int y;
  int z;
  
  public A_Base(A_Init init) 
  { 
    this.x = init.x;
    this.y = init.y;
    this.z = init.z;
  }
}
или есть ещё какой-нибудь хитрый паттерн?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.10.2016, 07:49
Ответы с готовыми решениями:

Базовый класс в иерархии наследования. Вывод свойств объектов
Здрасти. Помогите исправить функцию print_out именно таким образом: void print_out() { void print_out_prop1(); //...

typeid определяет тип указателя на базовый класс, как тип "базовый класс". Вне зависимости от присвоенного ему значения
Вот код: #include <iostream> #include <string> #include <conio.h> #include <windows.h> #include <typeinfo> using...

Базовый класс Complex и производный класс для реализации квадратных матриц
1) Создайте базовый класс Complex (комплексное число) для реализации комплексных чисел в алгебраической форме и основных операций с ними:...

7
 Аватар для tarasalk
1992 / 1216 / 440
Регистрация: 13.06.2013
Сообщений: 4,115
10.10.2016, 10:32
Да, пожалуй такая проблема есть, но странно я с ней ни разу не сталкивался)
Может вам агрегирование попробовать вместо наследования?
0
Модератор
Эксперт функциональных языков программирования
3134 / 2281 / 469
Регистрация: 26.03.2015
Сообщений: 8,877
11.10.2016, 15:46
Цитата Сообщение от Pandasama Посмотреть сообщение
как в приличном обществе принято решать такую задачу
Так:
Цитата Сообщение от Pandasama Посмотреть сообщение
придется во всей иерархии классов менять определение конструктора
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4575 / 2774 / 491
Регистрация: 28.04.2012
Сообщений: 8,765
12.10.2016, 07:10
Цитата Сообщение от tarasalk Посмотреть сообщение
Может вам агрегирование попробовать вместо наследования?
Но тогда придётся кучу методов делегировать. Я не знаю, как с этим обстоят дела в C#, но в Java это будет куча boilerplate кода. =)

Например
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import java.util.Arrays;
 
interface Copyable<T> {
 
    T copy();
}
 
interface Content {
 
    String[][] content();
}
 
interface HasX {
 
    int getX();
 
    void setX(int x);
}
 
interface HasY {
 
    int getY();
 
    void setY(int y);
}
 
interface HasName {
 
    String getName();
 
    void setName(String name);
}
 
interface A extends HasX, HasY, Content {
}
 
class AImpl implements A, Copyable<AImpl> {
 
    private int x;
    private int y;
 
    public AImpl(int x, int y) {
        this.x = x;
        this.y = y;
    }
 
    @Override
    public int getX() {
        return x;
    }
 
    @Override
    public void setX(int x) {
        this.x = x;
    }
 
    @Override
    public int getY() {
        return y;
    }
 
    @Override
    public void setY(int y) {
        this.y = y;
    }
 
    @Override
    public String[][] content() {
        return new String[][]{
                {"x", Integer.toString(x)},
                {"y", Integer.toString(y)}
        };
    }
 
    @Override
    public AImpl copy() {
        return new AImpl(x, y);
    }
}
 
interface B extends A, HasName {
}
 
class BImpl implements B, Copyable<BImpl> {
 
    private AImpl a;
    private String name;
 
    public BImpl(AImpl a, String name) {
        this.a = a.copy();
        this.name = name;
    }
 
    @Override
    public int getX() {
        return a.getX();
    }
 
    @Override
    public void setX(int x) {
        a.setX(x);
    }
 
    @Override
    public int getY() {
        return a.getY();
    }
 
    @Override
    public void setY(int y) {
        a.setY(y);
    }
 
    @Override
    public String getName() {
        return name;
    }
 
    @Override
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String[][] content() {
        final String[][] aContent = a.content();
        final String[][] content = Arrays.copyOf(aContent, aContent.length+1);
        content[content.length-1] = new String[]{"name", name};
        return content;
    }
 
    @Override
    public BImpl copy() {
        return new BImpl(a, name);
    }
}


Хотя я предпочитаю композицию наследованию реализации.

А вообще…
Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(defgeneric content (object))
 
(defclass a ()
  ((#:x :initarg :x :accessor get-x)
   (#:y :initarg :y :accessor get-y)))
 
(defmethod content ((object a))
  (list (cons 'x (get-x object))
        (cons 'y (get-y object))))
 
(defclass b (a)
  ((#:name :initarg :name :accessor get-name)))
 
(defmethod content ((object b))
  (cons (cons 'name (get-name object))
        (call-next-method)))
 
(defun main ()
  (let ((a (make-instance 'a :x 1 :y 2))
        (b (make-instance 'b :x 3 :y 4 :name "Bee")))
    (format t "~a~%~a~%" (content a) (content b))))
 
(main)
=>
Bash
1
2
((X . 1) (Y . 2))
((NAME . Bee) (X . 3) (Y . 4))
Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#lang racket
 
(define a%
  (class object%
    (init-field x y)
 
    (define/pubment (content)
      (list* (cons 'x x)
             (cons y 'y)
             (inner (list) content)))
 
    (super-new)))
 
(define b%
  (class a%
    (init-field name)
 
    (define/augment (content)
      (list (cons 'name name)))
 
    (super-new)))
 
(define (main)
  (define a (new a% (x 1) (y 2)))
  (define b (new b% (x 3) (y 4) (name "Bee")))
  (displayln (send a content))
  (displayln (send b content)))
 
(main)
=>
Bash
1
2
((x . 1) (2 . y))
((x . 3) (4 . y) (name . Bee))
0
 Аватар для tarasalk
1992 / 1216 / 440
Регистрация: 13.06.2013
Сообщений: 4,115
12.10.2016, 08:22
Цитата Сообщение от korvin_ Посмотреть сообщение
Но тогда придётся кучу методов делегировать
Не обязательно. Можно через метод получить внутренний объект и вызвать любой его метод.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A {
    public function methodA() {
        echo 'A';
    }
}
 
class B {
    private $objA;
 
    public function __construct(A $objA) {
        $this->objA = $objA;
    }
 
    public function getA() {
        return $this->objA;
    }
}
 
$objA = new A;
$objB = new B($objA);
 
$objB->getA()->methodA();
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4575 / 2774 / 491
Регистрация: 28.04.2012
Сообщений: 8,765
12.10.2016, 19:38
Цитата Сообщение от tarasalk Посмотреть сообщение
Не обязательно. Можно через метод получить внутренний объект и вызвать любой его метод.
Ну, как вариант.

Добавлено через 7 часов 11 минут
Вот ещё в Go композиция и делегирование неплохо поддерживается

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main
 
import (
    "fmt"
)
 
type HasX interface {
    GetX() int
    SetX(int)
}
 
type HasY interface {
    GetY() int
    SetY(int)
}
 
type Contentable interface {
    Content() [][]string
}
 
type A struct {
    x int
    y int
}
 
func (a *A) GetX() int {
    return a.x
}
 
func (a *A) SetX(x int) {
    a.x = x
}
 
func (a *A) GetY() int {
    return a.y
}
 
func (a *A) SetY(y int) {
    a.y = y
}
 
func (a *A) Content() [][]string {
    return [][]string{
        {"x", fmt.Sprint(a.x)},
        {"y", fmt.Sprint(a.y)},
    }
}
 
type hiddenA struct {
    A
}
 
type B struct {
    hiddenA
    name string
}
 
func (b *B) Content() [][]string {
    return append(b.hiddenA.Content(), []string{"name", b.name})
}
 
func main() {
    a := A{
        x: 1,
        y: 2,
    }
    b := B{
        hiddenA: hiddenA{A{3, 4}},
        name: "Bee",
    }
    a.SetX(5)
    b.SetY(6)
    fmt.Println(a.Content())
    fmt.Println(b.Content())
}
https://play.golang.org/p/2bo-UoKRBf

В Go своеобразная система public/private (то, что с заглавной буквы — public), поэтому, если поле типа A внутри B хочется скрыть, нужно использовать private-тип-обёртку)
0
Эксперт С++
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
16.10.2016, 09:40
Pandasama, а паттерн Декоратор не подойдет? Посмотри книжку банды четырех по паттернам. Книжка легко гуглится по фразе "банда четырех".
Или в Википедии.
0
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,847
Записей в блоге: 2
19.10.2016, 18:01
Цитата Сообщение от Pandasama Посмотреть сообщение
Как у продвинутых ООП-товарищей принято поступать в подобных случаях?
Заводить отдельный класс/структуру, которая будет параметром для конструктора?
Это если параметров много, часто такие структуры называют "дескрипторами". Здесь мало, но x и у - четко видна структура, к тому же операторов на нее набежит мама дорогая. Поэтому правильно изначально делать что-то типа Point

Цитата Сообщение от Pandasama Посмотреть сообщение
Значит придется во всей иерархии классов менять определение конструктора, дописывая туда новый параметр z, хотя сами эти конструкторы мы не меняем - меняем только вызов родителя. И как-то это не очень хорошо.
Изменили базовую сущность - пошла волна изменений, это совершенно нормально
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.10.2016, 18:01
Помогаю со студенческими работами здесь

Описать базовый класс колоды карт и производный класс пасьянс
Здраствуйте! товарищи-программисты, помогите пожалуйста со следующим заданием: Создать колоду карт. Конструкторы колоды должны...

Класс: Дописать производный класс, дополняющий базовый и содержащий минимум 2 функции-члена...
Составьте программу на языке С#, которая должна содержать: 1) базовый класс в соответствии с вариантом; 2) производный класс,...

Класс: как обратиться к методу производного класса через итератор на базовый класс?
Есть абстрактный и два порожденных. Хочу создать например list&lt;Base*&gt; list1; затем добавляю себе в список: ...

Создать иерархию классов Figure
Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра. Создать производные классы: Rectangle...

Создать базовый класс Car (машина) и производный класс Lorry (грузовик): ООП ошибки
Создать базовый класс Car (машина), характеризуемый торговой маркой (строка), числом цилиндров, мощностью. Определить методы переназначения...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru