haker-kirik
Гость
|
|
« : 20-04-2008 19:56 » |
|
Вот простой пример: #include <string.h> #include <iostream> using namespace std;
class base { int base_i; public: base(){cout << "Default constructor\n";} base(char s[ ]){cout << "Copy constructor.\n";} };
class der:public base { public: der(char s[ ]) { if (strlen(s)==0) base("N/A"); else base(s); } };
int main() { int (a); der d1(""); der d2("sample str"); cin.get(); return 0; } По идее эта программа должна вывести два раза фразу "Copy constructor.", но на самом деле выводится следующее: Default constructor Copy constructor. Default constructor Default constructor Как это понимать???
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #1 : 20-04-2008 20:50 » |
|
Всё логично. Два Default Constructor (1я строка и 3я) - результат собственно конструирования объектов класса der. Вторая и четвёртая строки - результат локального создания двух безымянных объектов класса base в конструкторе класса der. Если сделаешь классу base ещё и деструктор с выводом сообщения, то легко в этом убедишься. Отдельный вопрос, почему при передаче строки во втором случае вызывается конструктор класса base без параметров. Если создавать именованный объект, то вызывается конструктор base(char s[]). Если неименованный, то конструктор по умолчанию, если не выполнить явное приведение типа base ((char*)str);.
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #2 : 21-04-2008 04:13 » |
|
согласен с Вадом. строку base(s) заменил на base d1(s); стал вызываться копирующий конструктор. очень странно. должен был и так вызваться. в твоём коде есть ряд ошибок поправил код думаю по коду поймёшь где твои ошибки class base { int base_i; public: base() { std::cout << "Default constructor\n"; } base(const char * s) { std::cout << "Copy constructor.\n"; } };
class der:public base { public: der(const char * s):base(s) { base b1(s); if (strlen(s)==0) base b2("N/A"); else base b3(s); } };
int _tmain(int argc, _TCHAR* argv[]) {
int (a); der d1(""); der d2("sample str"); return 0; }
компилил в VS2003 и в gcc
|
|
|
Записан
|
Странно всё это....
|
|
|
Вад
|
|
« Ответ #3 : 21-04-2008 05:07 » |
|
У меня осталось подозрение, что эти конструкции: if (strlen(s)==0) base ("N/A"); else base (s);
затевались ради вызова конструктора предка для объекта класса der из его же собственного конструктора. Если это так, то правильно будет делать, как у LogRus, der(const char * s):base(s) { ... }
|
|
|
Записан
|
|
|
|
haker-kirik
Гость
|
|
« Ответ #4 : 21-04-2008 14:11 » |
|
Вад, именно так. Я хочу вызвать конструктор класса base, а не создавать отдельный объект. Т.е. я хочу увеличить функциональность класса base за счёт создания производного класса der. В иной реализации данного примера можно и вовсе просто проверять в конструкторе der какое либо условие входящего аргумента и если оно (условие) не выполняется, то обект не создавать, иначе - вызывать конструктор класса base для инициализации нужных значений.
|
|
« Последнее редактирование: 21-04-2008 14:26 от Вад »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #5 : 21-04-2008 14:24 » |
|
В принципе, из конструктора конструктор предка можно вызвать и из тела, причём именно применительно к данному объекту. if (strlen(s)==0) base::base("N/A"); else base::base(s);
Если не указываешь область видимости, компилятор думает, что это конструирование безымянного объекта. А так - вызывает метод для текущего объекта. Но по-мне, так некрасиво рисовать Тогда уж вынести инициализацию в виртуальный метод А отменить конструирование не получится - или делай фабричный метод, или генери исключение из конструктора
|
|
« Последнее редактирование: 21-04-2008 14:29 от Вад »
|
Записан
|
|
|
|
haker-kirik
Гость
|
|
« Ответ #6 : 21-04-2008 21:09 » |
|
Вад, большое спасибо! Теперь-то всё заработало.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #7 : 16-05-2008 06:03 » |
|
Что заработало? Вообще ничего не понял... Собственно разбираться начал только из-за этого " А так - вызывает метод для текущего объекта." Никогда так не делал, понятно, что так не пишут, но сожрало любопытство, так вот вот исходник #include <iostream>
using namespace std;
class base { int base_i; public: base() { std::cout << "Default constructor\n"; } base(const char * s) { std::cout << "Copy constructor.\n"; } ~base() {std::cout << "destructor.\n";} };
class der:public base { public: der(const char * s):base(s) { if (strlen(s)==0) base::base("N/A"); else base::base(s); } };
int main(int argc, char * argv[]) { // int (a); der d1(""); der d2("sample str"); return 0; }
Результат выполнения Copy constructor. Copy constructor. destructor. Copy constructor. Copy constructor. destructor. destructor. destructor. Так вот при этом base::base("N/A"); и этом base::base(s); происходит создание двух временных объектов Кстати к создателю кода - вопрос, зачем вот это base("N/A"); твоя программа никогда не напишет в консоли "N/A" Итог все что-то поняли и порешали, я вот например ничего не понял... а смысл исходного кода так вообще для меня загадка... если уже внутри конструктора объекта вы решили его не создавать вам может помочь только исключение и более ничего. Итак повторю - я вообще ничего не понял ни одного поста (за исключением второго с которым полностью согласен). Прям моему удивлению нет предела... где должен вызываться конструктор по умолчанию (ну нет в программе места где он вызывается)? Это int (a); просто чума...
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Вад
|
|
« Ответ #8 : 16-05-2008 06:57 » |
|
lapulya, хм. Я не знаю, по какому принципу я трассировал подобный твоему код в прошлый раз, но почему-то посчитал, что метод вызывается для объекта. Судя по всему, впал в заблуждение - по крайней мере, сейчас мне не удаётся получить тот же результат, всё говорит о том, что происходит конструирование нового объекта. Пока будем считать, что это моя ошибка
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #9 : 16-05-2008 08:07 » |
|
Если жуть как надо воспользоваться конструктором как функцией, чисто для спортивного интереса (ну кто ж та делает в жизни...), то надо так переписать конструктор так der(const char * s):base(s) { if (strlen(s)==0) this->base::base("N/A"); else this->base::base(s); }
Еще раз говорю, это никому не надо, но для эксперимента покатит
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Вад
|
|
« Ответ #10 : 16-05-2008 08:17 » |
|
Вообще говоря, странно, потому что конструктор сам по себе не должен отличаться от других методов класса, кроме автоматической подстановки стартовой инициализации членов этого класса. Но автоматическая инициализация, за неимением явной - это лишь вопрос присутствия скрытого кода, все действия же применяются к уже выделенной в стеке или куче памяти, она же не при вызове метода выделяется. Поэтому не вижу, почему бы конструктору не вызываться повторно, хотя это и выглядит бессмысленным и/или опасным извращением ) Тем не менее, если уж вызов this->base::base() возможен, то не понимаю, почему base::base не даёт эффекта. Указание области видимости, вроде, ясно даёт компилятору понять, что речь идёт о методе, а не об объявлении безымянного объекта.
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #11 : 16-05-2008 08:56 » |
|
Оба на сколько эмоций ... Конечно, если до конца выверять, то в примерах нет ни одного копирующего конструктора. А в первом топике (вывод в консоль), как могла получиться четвертая строка Default constructor
|
|
|
Записан
|
while (8==8)
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #12 : 16-05-2008 10:13 » |
|
to sss...Конечно, если до конца выверять, то в примерах нет ни одного копирующего конструктора. А в первом топике (вывод в консоль), как могла получиться четвертая строка Default constructor ... Дык, я о чем и говорю! Даже больше, там ни первой, ни третьей строчки быть не может (что уж говорить о четвертой )! to ВадНе понятно почему ты считаешь, что при указании области видимости конструктор должен отрабатывать как функция ведь конструкция base::base() не чуть не лучше и не хуже this->base::base() с точни зрения написания (я про громоздкость), но во втором случае я гарантированно вызываю метод ,хотя подобные рассуждения это чистой воды философия... Все подобные вопросы решает стандарт, там это должно быть описано {если нас слышит Серега, то это я ему }
|
|
« Последнее редактирование: 16-05-2008 10:15 от lapulya »
|
Записан
|
С уважением Lapulya
|
|
|
McZim
|
|
« Ответ #13 : 16-05-2008 10:36 » |
|
base::base() не чуть не лучше и не хуже this->base::base() меньше прерываний процессора
|
|
|
Записан
|
The CBO without stats is like a morning without coffee. (c) T.Kyte.
|
|
|
Вад
|
|
« Ответ #14 : 16-05-2008 14:28 » |
|
Не понятно почему ты считаешь, что при указании области видимости конструктор должен отрабатывать как функция Мне, напротив, непонятно, почему это не так. Ведь если просто base ещё можно по умолчанию интерпретировать как тип, то base::base() как тип интерпретироваться не должно. Или? Понятно, что это философия, и стандарт всех рассудит 12.1 2. A constructor is used to initialize objects of its class type. Because constructors do not have names, they are never found during name lookup; however an explicit type conversion using the functional notation (5.2.3) will cause a constructor to be called to initialize an object. [Note: for initialization of objects of class type see 12.6. ]
Только не понимаю, чем это мотивировано.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #15 : 17-05-2008 06:19 » |
|
this->base::base() а это компилируется что ли ? и при чём тут прерывания процессора, чёта я не совсем понял
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #16 : 17-05-2008 10:55 » |
|
Ну а чего бы ему не компилироваться то? Почему вообще появились в этом сомнения?
Про прерывания процессора я тоже не понял, но воизбежании флуда для себя решил что это шутка (типа для написания последней фразы надо больше писать и типа на обработку этого потребуется больше тактов процессора ))) )
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #17 : 17-05-2008 14:45 » |
|
lapulya, this->base::base() - ну не знаю , так то компилится, я попробовал , но как-то непривычно и криворуко запись выглядит
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #18 : 17-05-2008 20:31 » |
|
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #19 : 17-05-2008 21:07 » |
|
lapulya, а я и так не делаю Мне проще написать function(); или this->function(); //хотя тоже лишнее а это this->Base::function() - это для статик-мембера
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #20 : 17-05-2008 21:14 » |
|
Не, для статик мембера это вообще не скомпилируется (тут же у тебя this написано, а для статика никакого this по определению быть не может), для статика так
Base::function();
да и то если вызов идет из внешнего места для скласса, мембером которого является данный статик метод, а если мы в границах родного класса, тогла и так
function();
прокатит
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #21 : 17-05-2008 21:23 » |
|
lapulya, я не проверял про this->Base::function() для статика. А ты проверял ?
просто в любом случае я так никогда не вызываю this->....
поэтому и не парюсь никогда такими надуманными проблемами )
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #22 : 17-05-2008 21:29 » |
|
Алексей1153++, Это иногда полезно. Например такой случай void SomeClass::setColor(int color) { this->color = color; }
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #23 : 17-05-2008 21:31 » |
|
Finch, ду ну, зачем себя запутывать ) Это решается проще
void SomeClass::setColor(int color_in) { m_color = color_in; }
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #24 : 17-05-2008 21:45 » |
|
Алексей1153++, Я не люблю давать сто имен для одной сушности. Иногда приходится и так писать. Хотя в последнее время внутрении переменные класса я стал обозначать через приставку _ , то есть _color.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #25 : 17-05-2008 21:53 » |
|
Опааа to Алексей1153++, я был не прав, беру свои слова обратно для статик функции такой вызов this->Base::function() корректен, по крайней мере со стороны MS VS 2005 С++ компилятора.
Для статистики ))) все мемберы переменные у меня имеют приставку the типа class A { int theNumber; };
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #26 : 18-05-2008 08:18 » |
|
Алексей1153++, Я не люблю давать сто имен для одной сушности. Иногда приходится и так писать.
ну, всё зависит от привычки и внимательности Я вот часто бываю невнимателен, поэтому использую префиксы для автокомментирования переменных, что ооочень мне помогает все мемберы переменные у меня имеют приставку the типа class A { int theNumber; };
а я ставлю "m_" )
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #27 : 31-05-2008 18:49 » |
|
Вот простой пример: ... По идее эта программа должна вывести два раза фразу "Copy constructor.", но на самом деле выводится следующее: Default constructor Copy constructor. Default constructor Default constructor Как это понимать??? На самом деле твою задачу надо было решать так: #include <string.h> #include <iostream> using namespace std;
class base { int base_i; public: base(){cout << "Default constructor\n";} base(char s[ ]){cout << "Copy constructor: " << s << ".\n";} };
class der:public base { public: der(char s[ ]) :base(strlen(s)==0 ? "N/A" : s) { //if (strlen(s)==0) // base("N/A"); //else // base(s); } };
int main() { int (a); der d1(""); der d2("sample str"); cin.get(); return 0; }
Результат такой, как и ожидал автор: Copy constructor: N/A. Copy constructor: sample str.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #28 : 31-05-2008 19:23 » |
|
LifeMaker, он же не правильного вывода хотел добиться, а понять порядок вызовов )
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #29 : 31-05-2008 19:49 » |
|
Отдельный вопрос, почему при передаче строки во втором случае вызывается конструктор класса base без параметров. Если создавать именованный объект, то вызывается конструктор base(char s[]). Если неименованный, то конструктор по умолчанию, если не выполнить явное приведение типа base ((char*)str);.
меня четвёртая строка тоже сначала в тупик поставила. вроде по всем правилам должен был base(char s[ ]) сработать. но потом всё-таки до меня дошло. C++ позволяет при объявлении переменной взять её название в скобки. Например: int (a); char (*c); float (m[15]);
Вполне валидные, компилящиеся и работающие объявления. Полностью эквивалентные этому: int (a); char (*c); float (m[15]);
В данном случае компилятор воспринял строку "base(s);" как объявление локальной переменной типа base с именем s (да, C++ разрешает давать локальным переменным имена совпадающие с именами формальных параметров). Убедиться, что это действительно так можно изменив код следующим образом: #include <string.h> #include <iostream> using namespace std;
class base { const char* who_am_i; public: base() { cout << "Default constructor\n"; who_am_i = "I am constructed without parameters\n"; } base(char s[ ]) { cout << "Copy constructor.\n"; who_am_i = "I am constructed with char s[] parameter\n"; } void print_about_yourself() { cout << who_am_i; } };
class der:public base { public: der(char s[ ]) { if (strlen(s)==0) base("N/A"); else { base(s); s.print_about_yourself(); } } };
int main() { int (a); der d1(""); der d2("sample str"); cin.get(); return 0; }
Вывод: Default constructor Copy constructor. Default constructor Default constructor I am constructed without parameters
|
|
|
Записан
|
|
|
|
|