Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.97/37: Рейтинг темы: голосов - 37, средняя оценка - 4.97
140 / 72 / 26
Регистрация: 29.06.2015
Сообщений: 186
1

Как обратится к обьекту класса, являющегося наследником абстрактного класса

31.07.2015, 23:58. Показов 6946. Ответов 131
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!
У меня есть 4 класса: один виртуальный, следующие 2 - наследуют виртуальный класс и последний класс содержит
указатель на виртуальный класс (динамический массив, который растет от методов buildCar и buildTruck).
eFuel - это также класс, который содержит еще класс, но в данном вопросе они не принимают участия.
Вопрос: как через указатель четвертого класса доступится к наследующим классам?
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
class aGasStation
{
    friend class bCar;
    friend class cTruck;
protected :
    double A92;
    double A95;
    double A98;
    int cistern92;
    int cistern95;
    int cistern98;
public:
    aGasStation ();
    ~aGasStation ();
    virtual void print () = 0;
};
 
class bCar : public aGasStation
{
    eFuel fuelcar;
public:
    bCar ();
    ~bCar ();
    void print ();
};
 
class cTruck  : public aGasStation
{
    eFuel fueltruck;
public:
    cTruck ();
    ~cTruck ();
    void print ();
};
 
class dChainOfGasStation
{
    aGasStation *base;
    double money;
    static int size;
public:
    dChainOfGasStation ();
    ~dChainOfGasStation ();
    friend void buildCar (dChainOfGasStation *tmp);
    friend void buildTruck (dChainOfGasStation *tmp);
};
C++
1
2
3
4
5
6
7
8
void main ()
{
    dChainOfGasStation base;
    buildCar (&base);
    buildCar (&base);
    buildTruck (&base);
    buildCar (&base);   
}
Пытаюсь таким способом в main(), но знаю что base[0] - это private, а сделать его public противоречит правилам С++
C++
1
base.base[0]->print();
Можно написать set-метод, но каким образом это сделать я не знаю.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.07.2015, 23:58
Ответы с готовыми решениями:

как узнать,является данный объект класса А1 наследником класса А2
Всем привет)есть классы S, A1, A2, B1, B2. Иерархия наследования следующая S - Является...

Как полю класса А обратится к приватной функции класса А?
Есть лифт (класс "Elevator "), в котором находится кнопка (класс "Button"). При нажатии на кнопку...

Как обратиться из конструктора базового абстрактного класса к свойству-массиву класса наследника
Добрый день. Подскажите как обратиться из конструктора базового абстрактного класса к...

Поместить в динамически расширяемый массив объекты класса, производные от базового абстрактного класса
Помогите пожалуйста новичку! (мне). Я хочу создать динамически расширяющийся массив указателей...

131
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 16:01 81
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от DrOffset Посмотреть сообщение
Здесь нет нарушения инкапсуляции, есть другой подход к организации интерфейса.
Естественно нет, ибо один класс не лезит в другой...
Да и по сути, что это код делает?
К примеру чем тут конструктор не устроил?

Добавлено через 3 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
1.
пользователя не касается, что там под капотом чужого класса.
Цитата Сообщение от hoggy Посмотреть сообщение
2.
разработчик знает, что под капотом его собственного класса.
Ну.. ну... пользователь это разработчик спустя несколько месяцев .... когда все уже подзабылось.

Добавлено через 1 минуту
Цитата Сообщение от hoggy Посмотреть сообщение
имя не должно никак светить подробности реализации.
Имя нет, о чем я и пытался сказать, а вот "фриенд-объявление" неплохо бы что бы говорило, точнее сказать что давало больше информации об "отношениях" к этому классу.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 16:06 82
Цитата Сообщение от Avazart Посмотреть сообщение
Ну.. ну... пользователь это разработчик спустя несколько месяцев .... когда все уже подзабылось.
ну и что?

если разраб через полгода собственный код вразуметь не в состоянии - ну его трудности.
значит такой разраб.

"пьяный проспится, дурак - никогда"(ц)Петр 1.


и кстати, чем меньше всякой ботвы, тем проще код.
когда я читаю чужой код,
я смотрю на то, что код делает по факту.
а не на то, чего он мог бы сделать,
или не мог.

Добавлено через 56 секунд
Цитата Сообщение от Avazart Посмотреть сообщение
Имя нет, о чем я и пытался сказать, а вот "фриенд-объявление" неплохо бы что бы говорило, точнее сказать что давало больше информации об "отношениях" к этому классу.
если вы считаете, что имя не достаточно понятное - ну дайте более понятное.
0
18841 / 9840 / 2408
Регистрация: 30.01.2014
Сообщений: 17,281
01.08.2015, 16:22 83
Цитата Сообщение от Avazart Посмотреть сообщение
Да и по сути, что это код делает?
К примеру чем тут конструктор не устроил?
Это демонстрационный пример. Детали не играют роли, главное там - это строки 9 и 16, которые демонстрируют ноль отличий, с точки зрения доступа к данным класса.

А вообще есть разные варианты применения такого. Когда конструктор спрятан, чтобы кто попало не мог создать объект. Это как раз пример усиления инкапсуляции, путем накладывания дополнительных ограничений. Ты же сам с подобного примера и начал. В любом случае, без конкретной задачи целесообразность подобного обсуждать бессмысленно. В С++ есть много идиом, которые без упоминания конкретной задачи могут показаться бредом.

PS. Вообще, если интересно, демонстрационный пример использовал в основе эту идиому: https://en.wikibooks.org/wiki/... onstructor
Однако это напрямую не относится к обсуждаемому вопросу.
2
70 / 64 / 40
Регистрация: 17.02.2014
Сообщений: 265
01.08.2015, 16:48 84
Цитата Сообщение от DrOffset Посмотреть сообщение
class Base {};
class C : public Base
{
public:
* * friend std::unique_ptr<C> create();
private:
* * C() {}
int v;
};
std::unique_ptr<C> create()
{
* * std::unique_ptr<C> x(new C());
* * x->v = 10;
* * return x;
}
Это называется как загнать себя в угол с инкапсуляцией.По идеи пример не имеет право на жизнь. Потому как я не смогу сделать вот так.
C++
1
2
3
4
5
6
7
8
class D : public C
{
};
int main()
{
    D d;
    return 0;
}
Класс C сам должен быть инкапсулирован . Чтобы юзер не смог вообще его видеть.Или нам нужно решение в виде костылей ?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 17:02 85
Цитата Сообщение от smartpointer Посмотреть сообщение
Это называется как загнать себя в угол с инкапсуляцией.По идеи пример не имеет право на жизнь. Потому как я не смогу сделать вот так.
Цитата Сообщение от smartpointer Посмотреть сообщение
Класс C сам должен быть инкапсулирован . Чтобы юзер не смог вообще его видеть.Или нам нужно решение в виде костылей ?
сложно предполагать, что вы понимаете под инкапсуляцией.
но в голове у вас конкретная каша.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 17:07 86
Цитата Сообщение от DrOffset Посмотреть сообщение
Это демонстрационный пример. Детали не играют роли, главное там - это строки 9 и 16, которые демонстрируют ноль отличий, с точки зрения доступа к данным класса.
Да как раз дьявал в деталях.

Цитата Сообщение от DrOffset Посмотреть сообщение
В С++ есть много идиом, которые без упоминания конкретной задачи могут показаться бредом.
А я о чем... твой код бред .. непонятно что делает, для чего и как.
Класс Base пустой.... явно чего то нехватает...

Цитата Сообщение от hoggy Посмотреть сообщение
и кстати, чем меньше всякой ботвы, тем проще код.
Добавлено через 2 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
и кстати, чем меньше всякой ботвы, тем проще код.
Добро пожаловать в Си и Asm там все просто...

Добавлено через 48 секунд
Цитата Сообщение от hoggy Посмотреть сообщение
я смотрю на то, что код делает по факту.
а не на то, чего он мог бы сделать,
или не мог.
Ну вот и я про то нужно смотреть, не интуитивно...

Добавлено через 45 секунд
Цитата Сообщение от hoggy Посмотреть сообщение
если вы считаете, что имя не достаточно понятное - ну дайте более понятное.
Так а я о чем нет таких средств в С++.
0
70 / 64 / 40
Регистрация: 17.02.2014
Сообщений: 265
01.08.2015, 17:17 87
Цитата Сообщение от hoggy Посмотреть сообщение
сложно предполагать, что вы понимаете под инкапсуляцией.
Так же как и вы. Тык или не ?
Цитата Сообщение от hoggy Посмотреть сообщение
но в голове у вас конкретная каша.
Ну так приведите контр-пример или типа классы не могут быть скрытыми ?
P.S меньше читайте всяких умников - больше пишите кода, иначе только забьете голову всяким бредом так и не научившись кодить
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 17:31 88
Цитата Сообщение от Avazart Посмотреть сообщение
Добро пожаловать в Си и Asm там все просто...
мне и на плюсах не плохо.

Цитата Сообщение от Avazart Посмотреть сообщение
Ну вот и я про то нужно смотреть, не интуитивно...
если вам понадобилось смотреть потроха класса,
значит вы в любом случае будете это делать.

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

ничто не мешает писать понятный код.

откуда у вас такая нужда возникла,
это вопрос отдельный, и открытый.

явно не из-за декларации в приватной части класса некого френда.

Цитата Сообщение от Avazart Посмотреть сообщение
Так а я о чем нет таких средств в С++.
существующих возможностей языка выше крыше,
для написания понятного кода.

Цитата Сообщение от smartpointer Посмотреть сообщение
Так же как и вы. Тык или не ?
похоже, что не.

Цитата Сообщение от smartpointer Посмотреть сообщение
Ну так приведите контр-пример или типа классы не могут быть скрытыми ?
1.
Инкапсуляция данных - это не сокрытие данных.

2.
в примере выше у класса был закрыт конструктор.
автор этого кода сделал это специально.

ваша реакция на это показывает,
что вы не осознаете сути момента.

в частности:
Цитата Сообщение от smartpointer Посмотреть сообщение
Потому как я не смогу сделать вот так.
вот именно для этого конструктор и был сознательно закрыт его создателем.

что бы такие как вы,
которые не в теме,
не смогли отстрелить себе ноги.

Добавлено через 1 минуту
Цитата Сообщение от smartpointer Посмотреть сообщение
P.S меньше читайте всяких умников - больше пишите кода, иначе только забьете голову всяким бредом так и не научившись кодить
спасибо за заботу.
правда я уже староват для таких советов.
0
18841 / 9840 / 2408
Регистрация: 30.01.2014
Сообщений: 17,281
01.08.2015, 17:47 89
Цитата Сообщение от Avazart Посмотреть сообщение
А я о чем... твой код бред .. непонятно что делает, для чего и как.
Класс Base пустой.... явно чего то нехватает...
Ну добавь туда что-нибудь
А вообще, все уже было сказано, повторяться не буду. Читай еще раз сначала.

Добавлено через 2 минуты
Цитата Сообщение от smartpointer Посмотреть сообщение
Это называется как загнать себя в угол с инкапсуляцией.
Нет, это называется ограничение на использование. Когда класс запрещают копировать - делают это по той же причине. Ограничивают использование. А нужно это оказалось настолько, что в новой редакции языка добавили возможность делать это из коробки.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 17:59 90
Цитата Сообщение от DrOffset Посмотреть сообщение
Читай еще раз сначала.
Да я код читаю, из него ничего не понять что вы хотели продемонстировать... пример фиг знает чего, ради не знаю чего.

Добавлено через 2 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
существующих возможностей языка выше крыше,
для написания понятного кода.
Ок, тогда насколько понятен этот код? И можно его улучшить/переписать/сделать понятнее?

Вспомогательное
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
#include <QCoreApplication>
#include <algorithm>
#include <iostream>
#include <functional>
#include <vector>
#include <cassert>
 
class NonCopyable
{
   protected:
    NonCopyable() {}
    ~NonCopyable() {}
  private:
    NonCopyable( const NonCopyable& );
    NonCopyable& operator=( const NonCopyable& );
};
 
template<typename P>
struct Deleter
{
   void operator()(P p){ delete p; }
};
 
template<typename C>
inline void deleteAll(const C& c)
{
  std::for_each( c.begin(),c.end(),
                 Deleter<typename C::value_type>() );
}
 
template<typename C>
inline void findAndErase(C& c,typename C::value_type v)
{
  c.erase( std::find(c.begin(),c.end(),v) );
}


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
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
class Graph;
class Vertex;
class Edge;
 
typedef std::vector<Vertex*> VContainer;
typedef std::vector<Edge*>   EContainer;
 
class DependencyManager
{
     friend class Graph;
     friend class Vertex;
     friend class Edge;
 
   private:
     static Vertex* createVertex(Graph* graph);
     static void destroyVertex(Vertex* vertex);
 
     static Edge* createEdge(Graph* graph,Vertex* from,Vertex* to);
     static void  destroyEdge(Edge* edge);
 
     static void clear(Graph* graph);
};
//----------------- Graph ------------------------------------
class Graph: private NonCopyable
{
     friend class DependencyManager;
   public:
     Graph();
     virtual ~Graph();
 
     const VContainer& vertices() const { return vertices_; }
     const EContainer& edges()    const { return edges_; }
 
     Vertex* addVertex();
     Edge*   addEdge(Vertex* from,Vertex* to);
     void clear();
 
   private:
     VContainer vertices_;
     EContainer edges_;
     bool clearMode_;
};
 
Graph::Graph():NonCopyable(),clearMode_(false)
{
 
}
 
Graph::~Graph()
{
   clear();
}
 
Vertex *Graph::addVertex()
{
   return DependencyManager::createVertex(this);
}
 
Edge *Graph::addEdge(Vertex *from, Vertex *to)
{
   return DependencyManager::createEdge(this,from,to);
}
 
void Graph::clear()
{
   DependencyManager::clear(this);
}
//------------------- Vertex ------------------------------------
class Vertex: private NonCopyable
{
    friend class DependencyManager;
  public:
    virtual ~Vertex();
 
    const EContainer& inEdges() const{ return inEdges_;  }
    const EContainer& outEdges()const{ return outEdges_; }
 
    Graph* graph()const{ return graph_; }
 
  private:
    Vertex(Graph* graph):graph_(graph){}
 
    Graph* graph_;
    EContainer inEdges_;
    EContainer outEdges_;
};
 
Vertex::~Vertex()
{
  DependencyManager::destroyVertex(this);
  std::cout<<"~Vertex()"<<std::endl;
}
//------------------- Edge ------------------------------------
class Edge: private NonCopyable
{
     friend class DependencyManager;
   public:
     virtual ~Edge();
     Vertex* from()const { return from_; }
     Vertex* to()  const { return to_; }
 
     Graph* graph()const{ return graph_; }
 
   private:
     Edge(Graph* graph,Vertex* from,Vertex* to);
 
     Graph* graph_;
     Vertex* from_;
     Vertex* to_;
};
 
Edge::Edge(Graph *graph, Vertex *from, Vertex *to)
  :NonCopyable(),graph_(graph),from_(from),to_(to)
{
 
}
 
Edge::~Edge()
{
    DependencyManager::destroyEdge(this);
    std::cout<<"~Edge()"<<std::endl;
}
//------------------- DependencyManager ------------------------
Vertex *DependencyManager::createVertex(Graph *graph)
{
  assert(graph);
  Vertex* vertex= new Vertex(graph);
  graph->vertices_.push_back(vertex);
  return vertex;
}
 
Edge *DependencyManager::createEdge(Graph *graph, Vertex *from, Vertex *to)
{
   assert(graph && from!=to && graph==from->graph_ && graph==to->graph_);
   Edge* edge= new Edge(graph,from,to);
   graph->edges_.push_back(edge);
   from->outEdges_.push_back(edge);
   to->inEdges_.push_back(edge);
   return edge;
}
 
void DependencyManager::destroyVertex(Vertex *vertex)
{
  assert(vertex);
  if(!vertex->graph_->clearMode_)
  {
    findAndErase(vertex->graph_->vertices_,vertex);
    deleteAll(vertex->inEdges_);
    deleteAll(vertex->outEdges_);
    vertex->inEdges_.clear();
    vertex->outEdges_.clear();
  }
}
 
void DependencyManager::destroyEdge(Edge *edge)
{
  assert(edge);
  if(!edge->graph_->clearMode_)
  {
    findAndErase(edge->graph_->edges_,edge);
    findAndErase(edge->from_->outEdges_,edge);
    findAndErase(edge->to_->inEdges_,edge);
  }
}
 
void DependencyManager::clear(Graph *graph)
{
  assert(graph);
  graph->clearMode_= true;
 
  deleteAll(graph->vertices_);
  deleteAll(graph->edges_);
 
  graph->vertices_.clear();
  graph->edges_.clear();
 
  graph->clearMode_= false;
}
 
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    Graph g;
    Vertex* v1= g.addVertex();
    Vertex* v2= g.addVertex();
 
    Edge* e= g.addEdge(v1,v2);
 
    delete v1;
 
    return a.exec();
}
Думаю из кода понятно что попытка смоделировать граф/ребра/вершины.
0
18841 / 9840 / 2408
Регистрация: 30.01.2014
Сообщений: 17,281
01.08.2015, 18:10 91
Цитата Сообщение от Avazart Посмотреть сообщение
Да я код читаю, из него ничего не понять что вы хотели продемонстировать... пример фиг знает чего, ради не знаю чего.
Там еще текст был. И этот текст связан причинно-следственной связью с предыдущим обсуждением и конкретно твоими словами об ограничении на доступ для friend конкретных полей или функций:
Цитата Сообщение от Avazart Посмотреть сообщение
friend Chain for CarGusStation::CarGusStation();
Этот пример поясняет логику, которая применяется для friend. Показывает что из себя friend представляет. Потому что попытка задуматься о таком, как в цитате выше, показывает, что ты неправильно понимаешь назначение friend в языке. Ты его воспринимаешь как "раскрывашку" данных кому не попадя, когда на самом деле это всего-лишь дополнительный способ описания интерфейсов. А неправильное применение как раз вытекает из понимания friend как простой раскрывашки данных. Если мы начнем относится к friend функциям\классам как к части интерфейса, то все станет на свои места.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 18:52 92
Цитата Сообщение от Avazart Посмотреть сообщение
Да я код читаю, из него ничего не понять что вы хотели продемонстировать... пример фиг знает чего, ради не знаю чего.
там в обоих случаях дизайн принципиально не отличается.
различие лишь в незначительных технических деталях:

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
#include <iostream>
#include <memory>
 
// --- найдите 10 принципиальных отличий
 
class Base {};
 
 
class C1 : public Base
{
public:
    static std::unique_ptr<C1> create()
    {
        std::unique_ptr<C1> x(new C1);
        x->v = 10;
        return x;
    }
    
private:
    C1() {}
    int v;
};
 
class C2 : public Base
{
public:
    friend std::unique_ptr<C2> create();
   
private:
    C2() {}
    
    int v;
};
std::unique_ptr<C2> create()
{
    std::unique_ptr<C2> x(new C2);
    x->v = 10;
    return x;
}
 
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    // --- смотреть на дизайн использования:
    auto obj1 = C1::create();
    auto obj2 = create();
}
в обоих случаях, создание объекта в обход фабрики запрещен.
в обоих случаях, в качестве фабрики использованы свободные функции.
в обоих случаях они - часть интерфейса класса

единственная разница в том,
что статическая-функция член существует в пространстве имени своего класса

а функция друг - вне пространства имени класса.

никаких других отличий в данном случае нет вообще.

господин DrOffset, безуспешно пытается донести до вас,
что друг класса - это на самом деле такая же полноценная, и полноправная часть класса,
как и другие его части.

недаром, что функцию член можно определить прямо в теле декларации класса:

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
#include <iostream>
#include <memory>
 
// --- найдите 10 принципиальных отличий
 
class Base {};
 
 
class C1 : public Base
{
public:
    static std::unique_ptr<C1> create()
    {
        std::unique_ptr<C1> x(new C1);
        x->v = 10;
        return x;
    }
    
private:
    C1() {}
    int v;
};
 
class C2 : public Base
{
public:
    friend std::unique_ptr<C2> create()
    {
        std::unique_ptr<C2> x(new C2);
        x->v = 10;
        return x;
    }
 
   
private:
    C2() {}
    
    int v;
};
std::unique_ptr<C2> create();
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    // --- смотреть на дизайн использования:
    
    auto obj1 = C1::create();
    
    auto obj2 = create();
    
}

однако поскольку, часто френдами злоупотребляют,
сливая потроха кому ни поподя,
нарушая инкапсуляцию,
и превращая таким образом код в лапшу,
то это и породило миф якобы о том,
что френды - зло, и нарушают инкапсуляцию.

Добавлено через 39 минут
Цитата Сообщение от Avazart Посмотреть сообщение
тогда насколько понятен этот код? И можно его улучшить/переписать/сделать понятнее?
да вроде все понятно:
есть 3 штуки элементов,
связка которых определяет модель данных.

и есть манагер, в который вынесена вся логика организации связей.

видимо, создатель решил вынести
лапшу связанную с организацией связи в одно место,
что бы не размазывать по всем этим классам.

с точки зрения архитектуры - вполне себе нормальны ход.

однако, я противник подобного дизайна:
C++
1
2
3
4
5
6
7
    Graph g;
    Vertex* v1= g.addVertex();
    Vertex* v2= g.addVertex();
 
    Edge* e= g.addEdge(v1,v2); //<--- закатали указатель
 
    delete v1; //ой, а чего это мы тут прибили ненароком?
C++
1
2
3
4
5
6
7
8
9
Edge *DependencyManager::createEdge(Graph *graph, Vertex *from, Vertex *to)
{
   assert(graph && from!=to && graph==from->graph_ && graph==to->graph_);
   Edge* edge= new Edge(graph,from,to);
   graph->edges_.push_back(edge);
   from->outEdges_.push_back(edge);   //<--- вах! вах!!! 
   to->inEdges_.push_back(edge);
   return edge;
}
нарушение правила:
кто захватывал, тот и должен освобождать.

я за то, что бы не использовать указатели там,
где по смыслу ожидаются живые объекты.

C++
1
2
3
4
5
    
    Graph g;
    Vertex& v1= g.addVertex();
    Vertex& v2= g.addVertex();
    g.addEdge(v1,v2);
2
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 19:01 93
Цитата Сообщение от hoggy Посмотреть сообщение
нарушение правила:
кто захватывал, тот и должен освобождать.
Так в том то и дело что нет явного владельца. Ибо логично что ребро не может сущетвовать отдельно от графа и от двух вершин которые оно соединяет.
Касательно указателя указателя так так и должно быть, указатель в обычных случаях может стать невалидным (Удаляем "родителя" удаляются "дочки", в данном случае у ребра два родителя, а с учетом графа - три)
0
140 / 72 / 26
Регистрация: 29.06.2015
Сообщений: 186
01.08.2015, 19:02  [ТС] 94
Цитата Сообщение от Mr.X Посмотреть сообщение
А зачем вам абстрактная заправка понадобилась? Это в задании так или вы сами придумали?
это такое задание

Создать консольное приложение, в котором реализовать работу сети автозаправок.
Заправки есть двух видов:
- Для легковых авто;
- Для грузовых авто.
Каждая заправка работает с тремя видами топлива: "А-92", "А-95", "А-98". Каждая заправка имеет ограниченный объем резервуара для хранения каждого вида топлива.
Функциональность сети:
1. Поставка топлива (отдельного вида отдельного заправку). Фиксируется дата поставки.
2. Отгрузка топлива (отдельного вида с отдельной заправки). Фиксируется дата отгрузки.
3. Просмотр статистики по каждой заправке: сколько запасов по видам топлива, история отгрузки пиломатериал по датам.
Все данные по запасам хранятся в файле.
Все данные по истории отгрузки хранятся в файле (другому).
4. Отчет по количеству отгруженного топлива (без деления по видам) по каждой заправке на конкретную дату (дата вводится пользователем). Определение заправки с максимальным показателем по отгрузке на конкретную дату (без деления по видам).

Реализовать абстрактный класс "Заправка". От него унаследовать два класса, которые представляют два вида заправок.
Реализовать класс "Сеть заправок".
Реализовать класс "Топливо".
Реализовать класс "Дата".
Реализовать обработку исключительных ситуциаций: попытки залить топлива больше, чем можно хранить, попытки отгрузить горючего больше, чем есть на заправке (по видам топлива).
Использовать библиотеку STL.
Проект должен быть разбит на header и cpp файлы. Каждый класс в отдельном файле.
Метод main () в отдельном файле.
Все данные загружать из файла.
Работу программы организовать в виде эргономичного меню.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 19:15 95
hoggy, Я с этой специально и привел пример с сильносвязными объектами.

Добавлено через 2 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
господин DrOffset, безуспешно пытается донести до вас,
что друг класса - это на самом деле такая же полноценная, и полноправная часть класса,
как и другие его части.
Ну полноценной она вряд ли может быть (хотя бы из выноса из пространства имен) и даже так, а как тогда трактовать дружественный класс?

Добавлено через 3 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Ты его воспринимаешь как "раскрывашку" данных кому не попадя, когда на самом деле это всего-лишь дополнительный способ описания интерфейсов.
В этом и проблема что как раз четко описать/зафиксировать интерфейс общенния/связей в нужной мере для двух и более классов нет возможностей.

Добавлено через 1 минуту
Цитата Сообщение от hoggy Посмотреть сообщение
я за то, что бы не использовать указатели там,
где по смыслу ожидаются живые объекты.
Ну так чет не уловил, в чем суть замены указателей ссылками?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 19:45 96
Цитата Сообщение от Avazart Посмотреть сообщение
Ну полноценной она вряд ли может быть (хотя бы из выноса из пространства имен) и даже так, а как тогда трактовать дружественный класс?
ну вот взять например, итератор:
C++
1
сontainer::iterator it = cont.begin();
формально - это отдельный класс от контейнера.
но логически (и на практике) - это часть интерфейса самого контейнера.

Цитата Сообщение от Avazart Посмотреть сообщение
Ну так чет не уловил, в чем суть замены указателей ссылками?
лучше отражает намерения автора кода, и контракты.

например, никто не сделает ничайно delete ссылке,
которую вернула функция.

и у пользователя не возникнет сомнений
касательно прав владения ресурсом.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 20:08 97
Цитата Сообщение от hoggy Посмотреть сообщение
но логически (и на практике) - это часть интерфейса самого контейнера.
Нет это не так.
Это прослойка/интерфейс между контейнерами и алгоритмами. Т.е нечто то что смещенно в сторону алгоритмов.
Само по себе существование итератора в отрыве от алгоритмов - нелепо. Как к примеру и friend оператор.
friend это такие себе "мостики" между несколькими "сущностями".

И пример DrOffset с использованием friend мне не понятен, мне кажется это необоснованным тем более кода есть альтернатива со статическим методом.
Да смысла в том что запрещать использования создания через конструктор я не уловил.
Только для запрета копирования? Так есть для этого прием NonCopyable причем которые не запрещает создавать объекты "не динамически".

Если подразумевалась фабрика/фабричный метод, так там по сути несколько классов, т.е дружественность на своем месте, месте "посредника". Хотя там и без дружественности вероятно можно обойтись...
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 20:13 98
Цитата Сообщение от Avazart Посмотреть сообщение
Так в том то и дело что нет явного владельца. Ибо логично что ребро не может сущетвовать отдельно от графа и от двух вершин которые оно соединяет.
Касательно указателя указателя так так и должно быть, указатель в обычных случаях может стать невалидным (Удаляем "родителя" удаляются "дочки", в данном случае у ребра два родителя, а с учетом графа - три)
владелец - граф.
который является контейнером для всех этих ребер и вершин.

он создает вершины/ребра.
он и должен их прибивать.

обратите внимание:
C++
1
Vertex(Graph* graph):graph_(graph){}
C++
1
Edge(Graph* graph,Vertex* from,Vertex* to);
элементы контейнера не самостоятельны.
они в принципе не могут существовать отдельно от своего графа.

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

наружу, как и любой другой нормальный контейнер,
граф выдает только ссылки на свои элементы.

и никто снаружи по этим ссылкам не должен их прибивать.
хорошая новость в том, что delete ссылкам не делают.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.08.2015, 20:22 99
Ок тогда как вы предполагаете убивать Vertex и Edge если не через delete ?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.08.2015, 20:27 100
Цитата Сообщение от Avazart Посмотреть сообщение
Это прослойка/интерфейс между контейнерами и алгоритмами. Т.е нечто то что смещенно в сторону алгоритмов.
забудьте на минуту слово "алгоритм".
оно вам только глаз замыливает.


есть контейнер.
и есть вызывающая сторона.
которая может выполнять манипуляции над контейнером.

все действия над контейнером осуществляются
посредством его интерфейса.

например, что бы получить элемент контейнера,
необходимо использовать его интерфейс.

это можно сделать, дернув напрямую функцию-член.
или дернув итератор.


а в том что касается алгоритмов:

в итераторы вынесли нечто общее для всех контейнеров.
и стандартизировали.

то есть, алгоритмы тупо закладываются на интерфейс контейнеров.

Цитата Сообщение от Avazart Посмотреть сообщение
И пример DrOffset с использованием friend мне не понятен
я уже не знаю, как вам ещё помочь это понять.

представьте себе, что по какой то
прихоти программист реализовал с использованием френда,
а не на статической функции.

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

Цитата Сообщение от Avazart Посмотреть сообщение
Да смысла в том что запрещать использования создания через конструктор я не уловил.
а это вообще не существенно для примера-иллюстрации.

Добавлено через 54 секунды
Цитата Сообщение от Avazart Посмотреть сообщение
Ок тогда как вы предполагаете убивать Vertex и Edge если не через delete ?
так же как и создавались - через граф.
1
01.08.2015, 20:27
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.08.2015, 20:27
Помогаю со студенческими работами здесь

Метод абстрактного класса не видит переменные дочернего класса
есть abstract class A{ protected static $dir; public static function f(){} } и два класса...

Вызов функции класса, который наследуется от абстрактного класса
Предположим, что существует класс Base, который является абстрактным class Base{ public:...

Как инициализировать члены класса, являющегося параметром шаблона
#include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; template &lt;typename SomeClass&gt;...

Как обратится к объекту класса
Не могу обратится к объекту класса по индексу int main() { setlocale(LC_ALL, &quot;RUS&quot;); ...

Как обратиться к конструктору абстрактного класса
В Java это можно сделать таким образом: public abstract class AbClass { AbClass(int a) { }...

Как вызвать функцию из абстрактного класса?
Здравствуйте. Как мне вызвать функцию input с помощью указателя из класса People? При этом не...


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

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru