Re[5]: Output
От: GGoga  
Дата: 04.07.08 12:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Тогда думаю, Вам это будет интерессно.


Огромное СПАСИБО!!! Очень интересно
Re[3]: Output
От: GGoga  
Дата: 04.07.08 12:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Складывается впечатление, что Вы пологаете, что в экзепляре класса D существует два объекта А.


Интересно, почему Вы так решили???
Объясню свою логику (совпадающую с работой приложения):
destructor A — удаление локального объекта в функции А::fun2(A obj){}
destructor D — деструктор класса D после вызова оператора delete ptr
destructor C — деструктор родительского класса С объекта ptr
destructor B — деструктор родительского класса В объекта ptr
destructor A — деструктор родительского класса А объекта ptr
destructor A — деструктор класса А объекта one

А если Вы так не полагаете, хотелось бы услышать конкретное объяснение.
Re[4]: Output
От: Аноним  
Дата: 04.07.08 12:46
Оценка:
Нет, все правильно
Re[5]: Output
От: Аноним  
Дата: 04.07.08 19:08
Оценка:
Простите что встреваю, но прошу ответить 1 и 2 варианты кода полностью идентичны
или между ними есть разница
//1
class B{
 public:
   virtual void f(){cout<<"B\n";}
};

class D: public B{
 public:
   void f(){cout<<"B\n";}
};


//2
class B{
 public:
   void f(){cout<<"B\n";}
};

class D: public B{
 public:
   void f(){cout<<"B\n";}
};
Re[4]: Output
От: Alex Alexandrov США  
Дата: 04.07.08 20:25
Оценка:
Здравствуйте, GGoga, Вы писали:

GG>Здравствуйте, Кодт, Вы писали:


К>>...а при чём здесь "интуитивно"? Это и логически тоже понятно.


GG>Просто я всегда думал (теперь уже понимаю, что не правильно!!!), что для переопределения виртуального метода всегда необходимо указывать ключевое слово virtual (по крайней мере, я так всегда делал), а теперь понял и буду знать, что нет


Только не увлекайся. Иногда C++ позволяет то, чего не надо. Указывай лучше. Потомки спасибо скажут.
It's kind of fun to do the impossible (Walt Disney)
Re[6]: Output
От: Аноним  
Дата: 04.07.08 22:16
Оценка:
VMT
Re[6]: Таки надо для чего? :)
От: shrecher  
Дата: 05.07.08 02:13
Оценка:
Здравствуйте, Erop, Вы писали:


E>Но вот для чего надо точно знать порядок конструирования виртуальных и невиртуальных баз я, например, не знаю.


На самом деле знать тут ничего не надо. Надо просто уметь мыслить логически. Правило просто — потомок всегда может использовать предка, соответственно предок должен жить дольше потомка.

к примеру, есть код:

class A
{
protected:
    char *m;
    A() { m = new char[10]; }
};

class B : public A
{
public:
    B() { memset( m, 0, 10); }
};


порядок вызовов контсрукторов очевиден: А (базовый класс) обязан быть вызван до потомка, т.к. В может использовать члены A. Аналогично и в деструкторах: потомок должен быть унчтожен первым, т.к. в дестукторе можно опять использовать челены предка. Если бы было наоборот (предок уничтожен первый), то потомок просто грохнется в деструкторе.

Тоже и с дефолтными конструкторами членов — они создаются после создания предков.
Re[7]: Таки надо для чего? :)
От: Erop Россия  
Дата: 05.07.08 02:38
Оценка:
Здравствуйте, shrecher, Вы писали:

S>Здравствуйте, Erop, Вы писали:



E>>Но вот для чего надо точно знать порядок конструирования виртуальных и невиртуальных баз я, например, не знаю.


S>На самом деле знать тут ничего не надо. Надо просто уметь мыслить логически. Правило просто — потомок всегда может использовать предка, соответственно предок должен жить дольше потомка.


Вообще-то, если этого соображения достаточно для ответа на вопрос, то по моему мнению
Автор: Erop
Дата: 03.07.08
он не сложный и приемлимый.

а вот, если, таки надо уметь восстановить порядок точно, то, IMHO, это лишнее. Не в смысле не нужно знать, а в смысле не имеет смысла требовать от кандидата таких знаний

S>Тоже и с дефолтными конструкторами членов — они создаются после создания предков.

Дефолтные конструктира у членов записаны или нет -- для порядка их конструирования НЕ ВАЖНО!
С базами, кстати, такая же фигня...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Таки надо для чего? :)
От: shrecher  
Дата: 05.07.08 04:15
Оценка:
Здравствуйте, Erop, Вы писали:


E>а вот, если, таки надо уметь восстановить порядок точно, то, IMHO, это лишнее. Не в смысле не нужно знать, а в смысле не имеет смысла требовать от кандидата таких знаний


так из знания принципа (база живет дольше чем потомок) порядок восстановился практически тожно.

S>>Тоже и с дефолтными конструкторами членов — они создаются после создания предков.

E>Дефолтные конструктира у членов записаны или нет -- для порядка их конструирования НЕ ВАЖНО!
E>С базами, кстати, такая же фигня...

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

class X: public A, public B, public C, public D


очевидно, что порядок вызовов конструкторов будет А, В, С, D — не вижу обратной причины, конечно если компилятор не китаец
Re[6]: Output
От: Аноним  
Дата: 05.07.08 06:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Простите что встреваю, но прошу ответить 1 и 2 варианты кода полностью идентичны

А>или между ними есть разница
А>
А>//1
А>class B{
А> public:
А>   virtual void f(){cout<<"B\n";}
А>};

А>class D: public B{
А> public:
А>   void f(){cout<<"B\n";}
А>};
А>
А>
А>//2
А>class B{
А> public:
А>   void f(){cout<<"B\n";}
А>};

А>class D: public B{
А> public:
А>   void f(){cout<<"B\n";}
А>};
А>


http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D0%B8%D0%BC%D0%BE%D1%80%D1%84%D0%B8%D0%B7%D0%BC_%D0%B2_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0%D1%85_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F]
цитата

Виртуальный метод
Виртуальный метод (виртуальная функция) — в объектно-ориентированном программировании метод (функция) класса, который может быть переопределён в классах-наследниках так, что конкретная реализация метода для вызова будет определяться во время исполнения. Таким образом, программисту необязательно знать точный тип объекта для работы с ним через виртуальные методы: достаточно лишь знать, что объект принадлежит классу или наследнику класса, в котором метод объявлен.

Виртуальные методы — один из важнейших приёмов реализации полиморфизма. Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом, базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа. В некоторых языках программирования, например в Java, все функции-члены класса, кроме статических, являются виртуальными.

Базовый класс может и не предоставлять реализации виртуального метода, а только декларировать его существование. Такие методы без реализации называются «чисто виртуальными» (калька с англ. pure virtual) или абстрактными. Класс, содержащий хотя бы один такой метод, тоже будет абстрактным. Объект такого класса создать нельзя (в некоторых языках допускается, но вызов абстрактного метода приведёт к ошибке). Наследники абстрактного класса должны предоставить реализацию для всех его абстрактных методов, иначе они, в свою очередь, будут абстрактными классами.

Для каждого класса, имеющего хотя бы один виртуальный метод, создаётся таблица виртуальных методов VMT. Каждый объект хранит указатель на таблицу своего класса. Для вызова виртуального метода используется такой механизм: из объекта берётся указатель на соответствующую таблицу виртуальных методов, а из неё, по фиксированному смещению, — указатель на реализацию метода, используемого для данного класса. При использовании множественного наследования или интерфейсов ситуация несколько усложняется за счёт того, что таблица виртуальных методов становится нелинейной.

Пример на C++, иллюстрирующий отличие виртуальных функций от невиртуальных:

class B{
public:
  virtual void  function1 () { cout << "B::function1()" << endl; }
          void  function2 () { cout << "B::function2()" << endl; }
};
 
class D : public B
{
public:
  virtual void  function1 () { cout << "D::function1()" << endl; }
          void  function2 () { cout << "D::function2()" << endl; }
};
 
D*  pointer      = new D ();
B*  pointer_copy = pointer; //или B*  pointer_copy = new D ();
 
pointer->function1 ();
pointer->function2 ();
 
pointer_copy->function1 ();
pointer_copy->function2 ();

В этом примере класс 'B' определяет две функции, одну из них виртуальную, другую — нет. Класс 'D' переопределяет обе функции. Однако, казалось бы одинаковое обращение к функциям, даёт разные результаты. На выводе программа даст следующее:

D::function1()
D::function2()
D::function1()
B::function2()
То есть, в случае виртуальной функции, для определения реализации функции используется информация о типе объекта и вызывается «правильная» реализация, независимо от типа указателя. При вызове невиртуальной функции, компилятор руководствуется типом указателя или ссылки, поэтому вызываются две разные реализации function2(), несмотря на то, что используется один и тот же объект.

Следует отметить, что в С++ можно, при необходимости, указать конкретную реализацию виртуальной функции, фактически вызывая её невиртуально:

pointer->B::function1 ();
для нашего примера выведет B::function1(), игнорируя тип объекта.



В дополнение http://c350.colo.hc.ru/Forum/message/13047.flat.aspx
Re: Output
От: Sergey Chadov Россия  
Дата: 05.07.08 09:19
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Что распечатает следующий код:


Ничего не напечатает...

Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 9: error: invalid redeclaration of member function "A::~A()"
          (declared at line 8)
      virtual ~A() { printf("destructor A\n"); }
              ^

"ComeauTest.c", line 38: error: return type of function "main" must be "int"
    So use int main() OR int main(int argc, char *argv[])
  void main()
       ^

3 errors detected in the compilation of "ComeauTest.c".
--
Sergey Chadov

... << RSDN@Home 1.2.0 alpha rev. 685>>
Re[2]: Output
От: Аноним  
Дата: 05.07.08 11:14
Оценка:
Код был изправлен здесь
Автор:
Дата: 03.07.08
Re[5]: Output
От: GGoga  
Дата: 05.07.08 12:25
Оценка:
Здравствуйте, Alex Alexandrov, Вы писали:

AA>Только не увлекайся. Иногда C++ позволяет то, чего не надо. Указывай лучше. Потомки спасибо скажут.


Да я как бы и не собирался так писать, тем более, что всегда привык все указывать явно (т.е. при переопределении всегда писал virtual и т.п.) Просто не всегда, например как в этой ситуации, люди разделяют мои привычки написания кода, а по-этому при получении на доработку такого кода приходится тратить время на "изучение" их техники кодирования А еще, как в случае данного топика, где автор проводил собеседование, прийдешь вот так к работодателю, а он тебе код с "подвохом" (хотя этого подвоха то на самом деле и нет), и прав в результате останется он, потому что именно я не знал, что допускается и такая форма записи
Но, как говорится, "век живи — век учись" Теперь на 1/100...0 "скиллов" в голове больше
Re[3]: Output
От: Left2 Украина  
Дата: 05.07.08 12:38
Оценка:
А>Понимаете, сегодня из 30 собеседуемых, на этот вопрос правильно ответоло только двое. Неужели он такой трудный?

Плохой вопрос. В С++ тааакая куча тонкостей, что все их знать просто невозможно. В итоге практикующему программисту желательно знать то, чем реально он реально пользуется в повседневной жизни. Так вот, лично я виртуальным наследованием не пользовался за десяток лет программирования на С++ ни разу. Более того, считаю его наличие признаком кривизны дизайна, хотя это только лично моё мнение не претендующее на истину в последней инстанции. Ну а писАть код который использует виртуальное наследование, да и при этом ещё и зависит от порядка вызова конструкторов — это уж совсем ни в какие ворота не лезет. Так что вопрос подходит только для того чтобы человека на собеседовании зачморить, но никак не для того чтобы выяснить адекватность его знаний и опыта.
Re[3]: Output
От: Sergey Chadov Россия  
Дата: 05.07.08 13:30
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Код был изправлен здесь
Автор:
Дата: 03.07.08


OK новый вариант:
Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 38: error: return type of function "main" must be "int"
    So use int main() OR int main(int argc, char *argv[])
  void main()
       ^

1 error detected in the compilation of "ComeauTest.c".
--
Sergey Chadov

... << RSDN@Home 1.2.0 alpha rev. 685>>
Re[3]: Output
От: ant_katcin Россия  
Дата: 06.07.08 09:52
Оценка:
Здравствуйте, <Аноним>, Вы писали:

V>>Насколько помню, сначало вызываются конструкторы виртуальных баз, потом обычных. Деструкторы, соответственно, наоборот. Вы об этом спрашиваете


А>Понимаете, сегодня из 30 собеседуемых, на этот вопрос правильно ответоло только двое. Неужели он такой трудный?


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

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

Как вопрос для собеседования имеет следующую ценность:
1) Если собеседник выражает возмущение кодом где такая зависимость важна. то + ему
2) По ответу надо убедиться, что он знает основы (виртуальные функции, вызов конструктора копирования)
3) Проследить что бы у собеседоваемого конструктор базового класса никогда не вызывался пойже конструктора дочернего. Это огромный минус и полное непонимание процессов конструирования.
4) Ну а если честно скажет, что не знает что такое виртуальное наследование, то маленький плюс за честность и погонять побольше по основам языка.

Все отстальные ошибки будут ИМХО незначительными, а если ещё и будут исправлены после наводящих вопросов то и вообще сходят на нет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1091>>
Re[6]: Таки надо для чего? :)
От: dandy  
Дата: 06.07.08 13:22
Оценка:
Здравствуйте, Erop, Вы писали:

E>Кстати, STL я использую ТОЛЬКО в демках, сэмплах, некоторых утилитах и прочем некоммерческом коде


Ты сам пишешь контейнеры и алгоритмы? Это маргинально.

It is my sacred and holy duty to see those guys suffer. (C) Douglas Adams

Re[2]: Топики лучше называть правильно...
От: dandy  
Дата: 06.07.08 16:00
Оценка:
Здравствуйте, Erop, Вы писали:

E>Например этот хорошо бы назвать както так: "Неужели я задаю на собеседовании плохие вопросы?" или, хотя бы, както так: "Хороший ли это вопрос для собеседования?"...


Если это был вопрос на собеседовании,
то после такого вопроса лучше сразу прощаться с собеседующим,
или продолжить разговор уже с его манагером.
Re[4]: Output
От: dont.avt Украина  
Дата: 07.07.08 08:40
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Это скорее дело хорошего или плохого стиля, но никак не ошибка.


Конечно, не ошибка. (стёб)

dont@localhost ~/work/tmp $ cat bla.cpp
void main()
{

}
dont@localhost ~/work/tmp $ g++ -o res bla.cpp
bla.cpp:1: error: ‘::main’ must return ‘int’
dont@localhost ~/work/tmp $ vim bla.cpp
dont@localhost ~/work/tmp $ cat bla.cpp
int main()
{

}
dont@localhost ~/work/tmp $ g++ -o res bla.cpp
dont@localhost ~/work/tmp $ gcc --version
gcc (GCC) 4.1.2 (Gentoo 4.1.2)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

В стандарте написано, что тип возвращаемого значения должен быть int, в противном случае он определяется реализацией.
Ну вот gcc все что не int считает ошибкой.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.