Здравствуйте, eao197, Вы писали:
>И еще, где можно прочитать про гламурность, очарование и шарм в программах?
Ну...
Смотри, что я придумал:
const означает, что мы не можем менять ноду.
DEEP_CONST означает ноду и всех её потомков.
#ifdef NDEBUG
#define DEEP_CONST const
#else
#define DEEP_CONST const volatile
#define DEEP_CONST_DEFINED
#endif
struct TreeNode
{
private:
TreeNode *right, *left;
int value;
public:
int get_val() DEEP_CONST { return value; }
void set_value(int i) { value = i; }
TreeNode *get_right() const { return right; };
TreeNode *get_left() const { return left; };
#if defined(DEEP_CONST_DEFINED)
TreeNode DEEP_CONST *get_right() DEEP_CONST { return right; };
TreeNode DEEP_CONST *get_left() DEEP_CONST { return left; };
#endif
};
void f(TreeNode DEEP_CONST *t)
{
t->get_right()->set_value(10); //ошибка
t->get_right()->get_val(); //ok
}
void g(TreeNode const *t)
{
t->get_right()->set_value(10); //ok
}
int main()
{
}
Может, у тебя есть ещё какие-то идеи?
10.01.06 22:22: Перенесено модератором из 'Мусор' — Кодт
Здравствуйте, _Winnie, Вы писали:
_W>const означает, что мы не можем менять ноду.
_W>DEEP_CONST означает ноду и всех её потомков.
_W>...
_W>struct TreeNode
_W>{
...
_W> TreeNode *get_right() const { return right; };
_W> TreeNode *get_left() const { return left; };
...
_W>};
...
_W>
_W>Может, у тебя есть ещё какие-то идеи?
Да, есть. Если метод get_right() является const, то и возвращать он должен const TreeNode *. А если мне нужен дочерний узел для изменения, но при этом я владею только константным указателем на родителя (уже странно, не находишь?), то не лучше ли сделать отдельные методы: get_writeable_right() и get_writeable_left()?
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, _Winnie, Вы писали:
_W>>const означает, что мы не можем менять ноду.
_W>>DEEP_CONST означает ноду и всех её потомков.
E>Да, есть. Если метод get_right() является const, то и возвращать он должен const TreeNode *.
Обрати внимание, класс называется Tree
Node
а не Tree.
а константность ноды не должна обозначать константность всего дерева.
Если бы класс назывался Tree, тогда бы да, get_right дожен сохранять константность подобъектов. Но поскольку это Node, а не Tree, то что справа и слева — не подобъекты.
> А если мне нужен дочерний узел для изменения, но при этом я владею только константным указателем на родителя (уже странно, не находишь?), то не >лучше ли сделать отдельные методы: get_writeable_right() и get_writeable_left()?
Ну и про модификатор const тоже можно сказать, что он не нужен, и что "просто не вызывайте функцию set_value" как и "не вызывайте *writable функции"
Достоинство квалификаторов — что компилятор проверит их сквозь десяток вызовов функций, во всей программе, даже в самом запутанном индусском коде-лапше.
Здравствуйте, _banned_dobrokot, Вы писали:
>> А если мне нужен дочерний узел для изменения, но при этом я владею только константным указателем на родителя (уже странно, не находишь?), то не >лучше ли сделать отдельные методы: get_writeable_right() и get_writeable_left()?
__>Ну и про модификатор const тоже можно сказать, что он не нужен, и что "просто не вызывайте функцию set_value" как и "не вызывайте *writable функции"
__>Достоинство квалификаторов — что компилятор проверит их сквозь десяток вызовов функций, во всей программе, даже в самом запутанном индусском коде-лапше.
Не понимаю, к чему ты это сказал. Если следовать моему предложению, то нет соглащений на уровне "просто не вызывайте вот это вот". Если есть const TreeNode и вызывается get_right, то получаем опять const TreeNode. Компилятор проверяет все квалификаторы, везде.
Но я бы, если бы мне пришлось делать какие-то подобные выкрутасы с деревьями, пошел бы еще дальше. Куда-то вот в эту степь:
class Writeable_Child_Accessor
{
public :
TreeNode * get_right() const;
TreeNode * get_left() const;
... /* Детали реализации */ ...
};
class Nonwriteable_Child_Accessor
{
public :
const TreeNode * get_right() const;
const TreeNode * get_left() const;
... /* Детали реализации */ ...
};
void f( Nonwriteable_Child_Accessor & node )
{
node.get_right()->set_value( 10 ); // БУМС! Получаем ошибку!
}
void g( Writeable_Child_Accessor & node )
{
node.get_right()->set_value( 10 ); // Все нормально.
}
Вот, в первом приближении, что-нибудь такое. Или дальше подумать, чтобы сам TreeNode реализовывал несколько интерфейсов (с тем, чтобы имея Nonwritable_Child_Accessor нельзя было через get_right()/get_left() получить Writeable_Child_Accessor для их дочерних узлов).