У Страуструпа нашел только такое применение const с функциями:
[code]
class A
{
...
public:
int f(void) const;
};
[/ccode]
что означает что функция f не может менять данные члены класса А. (Кстати, насколько я понимаю также не может вызывать не-const методы вложенных классов, однако может вызывать не-const методы классов, вложенных через указатель. Правильно?)
интересуют такие вопросы:
1. Можно ли объявлять глобальную функцию (не член класса) как "int g(void) const". Думается что нет, т.к. не вижу смысла. Если да, то что это значит?
2. Можно ли объявлять функцию или метод как "const int g(void)"? Т.е. может ли функция возвращать константный объект? В каких случаях это может применяться?
3. Если 2, то возможна ли комбинированная конструкция const int g(void) const?
I>что означает что функция f не может менять данные члены класса А. (Кстати, насколько я понимаю также не может вызывать не-const методы вложенных классов, однако может вызывать не-const методы классов, вложенных через указатель. Правильно?)
Не совсем понятно, что ты имеешь в виду под вложенными классами. Предположу, что речь идет о членах-данных
class A{/*...*/};
class B{/*...*/};
class C
{
A a_;
B b_;
void fun()const;
};
Если ты об этом, то да — в fun нельзя будет вызвать неконстантные функции-члены соответствующих классов.
Если a_ или b_ будет объявлен как mutable — то можно. Если они будут указателями (A * a_, B * b_) или ссылками — то опять же, можно.
I>интересуют такие вопросы:
I>1. Можно ли объявлять глобальную функцию (не член класса) как "int g(void) const". Думается что нет, т.к. не вижу смысла. Если да, то что это значит?
Нет, нельзя. Так же как и статическую функцию-член класса нельзя.
I>2. Можно ли объявлять функцию или метод как "const int g(void)"? Т.е. может ли функция возвращать константный объект? В каких случаях это может применяться?
Да, можно, но особого смысла в этом нет — то, что ты возвращаешь const int — будет r-value встроенного типа, поменять ты его не сможешь, даже если он неконстантный. Зато такая константность может понадобиться для объектов определенных тобой типов, чтоб для них (возвращаемых объектов) нельзя было вызвать неконстантные функции.
I>3. Если 2, то возможна ли комбинированная конструкция const int g(void) const?
Да, конечно, для нестатической функции-члена класса.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Не совсем понятно, что ты имеешь в виду под вложенными классами. Предположу, что речь идет о членах-данных
L_L>
L_L>class A{/*...*/};
L_L>class B{/*...*/};
L_L>class C
L_L>{
L_L> A a_;
L_L> B b_;
L_L> void fun()const;
L_L>};
L_L>
L_L>Если ты об этом, то да — в fun нельзя будет вызвать неконстантные функции-члены соответствующих классов. L_L>Если a_ или b_ будет объявлен как mutable — то можно. Если они будут указателями (A * a_, B * b_) или ссылками — то опять же, можно.
Да я имел в виду именно это. А как еще это можно было понять/назвать?
I>>интересуют такие вопросы:
I>>1. Можно ли объявлять глобальную функцию (не член класса) как "int g(void) const". Думается что нет, т.к. не вижу смысла. Если да, то что это значит?
L_L>Нет, нельзя. Так же как и статическую функцию-член класса нельзя.
Ну и слава богу .
I>>2. Можно ли объявлять функцию или метод как "const int g(void)"? Т.е. может ли функция возвращать константный объект? В каких случаях это может применяться?
L_L>Да, можно, но особого смысла в этом нет — то, что ты возвращаешь const int — будет r-value встроенного типа, поменять ты его не сможешь, даже если он неконстантный. Зато такая константность может понадобиться для объектов определенных тобой типов, чтоб для них (возвращаемых объектов) нельзя было вызвать неконстантные функции.
т.е. если я правильно понял это можно использовать например чтобы
class B
{
int f(void);
}
class A
{
B b;
public:
const B& get_b(void) {return b;}
};
...
{
A a();
a.get_b().f(); // compiler error!
}
Так?
Кроме того, наверное нельзя будет присвоить
A a();
const B b = a.get_b(); // ok
B bb = a.get_b(); // compiler error!
I>2. Можно ли объявлять функцию или метод как "const int g(void)"? Т.е. может ли функция возвращать константный объект? В каких случаях это может применяться?
Один пример уже приводили const SomeObj& CClass::GetSome();
Второй пример — постфиксный оператор++ I>3. Если 2, то возможна ли комбинированная конструкция const int g(void) const?
да
Здравствуйте, Ignoramus, Вы писали:
I>Кроме того, наверное нельзя будет присвоить I>
I> A a();
I> const B b = a.get_b(); // ok
I> B bb = a.get_b(); // compiler error!
I>
I>Правильно я понял?
Нет. На присваивание это не действует (а то, что ты написал — это вообще инициализация, а не присваивание).
запретить только можно будет инициализацию некостантных ссылок в стиле B& bb = a.get_b();
I>Да я имел в виду именно это. А как еще это можно было понять/назвать?
Есть еще понятие вложенного класса
class A
{
class NestedInA{};
};
I>т.е. если я правильно понял это можно использовать например чтобы I>Так?
Да, например так
I>Кроме того, наверное нельзя будет присвоить I>
I> A a();
I> const B b = a.get_b(); // ok
I> B bb = a.get_b(); // compiler error!
I>
I>Правильно я понял?
Ээээ, тут о присваивании речь не идет — в обоих случаях ОК и в обоих случаях это не присваивание, а инициализация копированием. Кроме того, A a(); — это объявление функции, а не объекта. И потому до ОК дело не дойдет, не скомпилится
class A
{
public:
A & operator = (int){return *this;}
};
const A fun(){return A();}
int main()
{
fun() = 1;
}
Вот скорее про такое присваивание ты говорил
Of course, the code must be complete enough to compile and link.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Ignoramus, Вы писали:
I>>Кроме того, наверное нельзя будет присвоить I>>
I>> A a();
I>> const B b = a.get_b(); // ok
I>> B bb = a.get_b(); // compiler error!
I>>
I>>Правильно я понял?
J>Нет. На присваивание это не действует (а то, что ты написал — это вообще инициализация, а не присваивание). J>запретить только можно будет инициализацию некостантных ссылок в стиле B& bb = a.get_b();
сорри, в данном примере я ошибся, я имел в виду конечно const B& b и B& bb.
Но если бы я объявил A::get_b как B get_b(), то тогда с помощью const также можно запретить инициализацию и самого объекта, правильно?
Кроме того если пример B bb = a.get_b(); разбить на B bb; bb = a.get_b();, то это тоже компилятор не пропустит, так? Т.е. не только инициализация но и присваивание запрещено? (для const B b понятно может быть только инициализация).
Здравствуйте, Lorenzo_LAMAS, Вы писали:
I>>Да я имел в виду именно это. А как еще это можно было понять/назвать? L_L>Есть еще понятие вложенного класса
L_L>
L_L>class A
L_L>{
L_L> class NestedInA{};
L_L>};
L_L>
Теперь понял . Честно говоря никогда так не делал. Это реально используется? Этот класс будет доступен для инстанциации вне класса А?
И это получается только объявление класса можно поместить как вложенное или после него сразу должно следовать определение члена? типа
class A
{
class NestedInA{} na;
}
L_L>Ээээ, тут о присваивании речь не идет — в обоих случаях ОК и в обоих случаях это не присваивание, а инициализация копированием.
Согласен, я за это уже ответил .
Кстати меня всегда интересовал вопрос — что происходит если я пишу
A a = A();
При этом некоторое время существует 2 экземпляра А или создается только один? Подозреваю что это зависит от интеллектуальности компилятора.
L_L>Кроме того, A a(); — это объявление функции, а не объекта. И потому до ОК дело не дойдет, не скомпилится
Не согласен. Я ведь не переопределил оператор (), так что это просто вызов конструктора без параметров.
Здравствуйте, Вадим Никулин, Вы писали:
ВН>Здравствуйте, Ignoramus, Вы писали:
I>>Упс, пропустил вот это: J>>>Нет. На присваивание это не действует
I>>А почему?
ВН>Mr. jazzer хотел сказать, что на каноническую форму присваивания это не действует.
ВН>Каноническая форма конструктора копирования: ВН>Obj( const Obj & );
ВН>Каноническая форма присваивания: ВН>Obj &operator = ( const Obj & );
Ну Вы меня совсем запутали На что действует и на что не действует?
I>Теперь понял . Честно говоря никогда так не делал. Это реально используется? Этот класс будет доступен для инстанциации вне класса А?
Ээээ, зависит от того, как ты его определил.
class A
{
class NestedInA{};
};
A::NestedInA a; // ошибка, так как вложенный класс недоступенclass B
{
public:
class NestedInB{};
};
B::NestedInB b; //нормально
ну и т.д. по поводу возможности "инстанцирования вне класса А" — тут, как это часто бывает в С++, чтоб получить исчерпывающий ответ лучше посмотреть определение языка.
I>И это получается только объявление класса можно поместить как вложенное или после него сразу должно следовать определение члена? типа
I>
I>class A
I>{
I> class NestedInA{} na;
I>}
I>
Ты можешь так сделать, но ты вовсе не обязан так делать.
I>Кстати меня всегда интересовал вопрос — что происходит если я пишу I>
I>A a = A();
I>
I>При этом некоторое время существует 2 экземпляра А или создается только один? Подозреваю что это зависит от интеллектуальности компилятора.
Да, у тебя тут инициализация копированием, но компилятор вполне может соптимизировать — убрать ненужное копирование.
I>Не согласен. Я ведь не переопределил оператор (), так что это просто вызов конструктора без параметров.
От твоего согласия тут увы, ничего не зависит. Попробуй скомпили такое :
struct A{
void fun(){}
};
int main()
{
A a();
a.fun();
}
после этого, мы обсудим, с чем ты несогласен
Of course, the code must be complete enough to compile and link.
L_L>>Кроме того, A a(); — это объявление функции, а не объекта. И потому до ОК дело не дойдет, не скомпилится I>Не согласен. Я ведь не переопределил оператор (), так что это просто вызов конструктора без параметров.
Блин, попробовал, реально получается что компилятор думает что это объявление функции. Вот если конструктор с параметром, то уже так не думает.
Как же так? Получается нельзя инстанциировать экземпляр класса вызвав его конструктор по умолчанию, если он не определен в классе. Выглядит как исключение из правил инициализации?
Здравствуйте, Ignoramus, Вы писали: I>Как же так? Получается нельзя инстанциировать экземпляр класса вызвав его конструктор по умолчанию, если он не определен в классе. Выглядит как исключение из правил инициализации?
Можно A a;
I>Как же так? Получается нельзя инстанциировать экземпляр класса вызвав его конструктор по умолчанию, если он не определен в классе. Выглядит как исключение из правил инициализации?
В теле функции ты можешь объявить функцию, а потому "выражение" вида A a(); это объявление функции.
Бывают случаи похуже и менее очевидные — это следствие синтаксической неоднозначности (если так можно выразиться).
class A
{
public:
A(int);
};
int main()
{
double d = 1.;
A nonObj(int(d));// - это опять объявление функции, возвращающей А и принимающей целое
A nonObj1(int()); // и даже это - объявление функции, ее параметр - указатель на функцию
A obj((int)d); // вот это объект
}
Of course, the code must be complete enough to compile and link.
Здравствуйте, LuciferMoscow, Вы писали:
LM>Можно A a;
При этом насколько я понимаю не будет вызван дефолтный конструктор, если он явно не определен в А.
Например
class A
{
int a;
};
class B
{
int b;
public:
B(void) {b = 0;}
}
{
int a; // значение a неопределено
A a; // A::a неопределено
B b; // B::b == 0
A a(); // если бы так можно было, то A::a == 0
B b(); // если бы так можно было, то эквивалентно B b;
}
Здравствуйте, Ignoramus, Вы писали:
I>Здравствуйте, LuciferMoscow, Вы писали:
LM>>Можно A a;
I>При этом насколько я понимаю не будет вызван дефолтный конструктор, если он явно не определен в А.
I>
I> A a(); // если бы так можно было, то A::a == 0
I> B b(); // если бы так можно было, то эквивалентно B b;
I>
I>Разве не так?
Так ведь дефолтный конструктор для A ничего не делает! Поэтому A::a не станет равным 0. Все-равно надо явно прописать конструктор по-умолчанию.
Здравствуйте, Ignoramus, Вы писали:
ВН>>Mr. jazzer хотел сказать, что на каноническую форму присваивания это не действует.
I>Ну Вы меня совсем запутали На что действует и на что не действует?
Вот что было написано у тебя:
A a; // круглые скобки удалены :)const B b = a.get_b(); // ok
B bb = a.get_b(); // compiler error! (1)
В строчке (1) вызывается конструктор копирования B. По-умолчанию он принимает const B &. Соответственно, никакой ошибки не будет, т. к. a.get_b() приводится к типу const B &.