Помнится, в свое время доводилось мне проводить собеседования по C++, к которым я относился очень серьезно и поэтому готовился основательно. У меня был список вопросов в стиле «взрыв мозгов», которыми я «пытал» соискателей. Хотя один раз чуть не произошел конфуз. Устраиваться на работу к нам пришел мужик с полным набором атрибутов настоящего программиста – длинные волосы, джинсы, футболка. Поскольку лет ему было около 40, а я только-только окончил институт, то у меня реально очко сжалось, т.к. было непонятно кто кого по C++ рвать будет, я его или он меня )). К счастью обошлось – он оказался джавистом, и пробовался на джавистскую вакансию. Здесь же хочу запостить список вопросов с короткими комментариями. Все вопросы разделены на 3 группы в зависимости от уровня соискателя. Вот вопросы для самого первого уровня...

Помнится, в свое время доводилось мне проводить собеседования по C++, к которым я относился очень серьезно и поэтому готовился основательно. У меня был список вопросов в стиле «взрыв мозгов», которыми я «пытал» соискателей. Хотя один раз чуть не произошел конфуз. Устраиваться на работу к нам пришел мужик с полным набором атрибутов настоящего программиста – длинные волосы, джинсы, футболка. Поскольку лет ему было около 40, а я только-только окончил институт, то у меня реально очко сжалось, т.к. было непонятно кто кого по C++ рвать будет, я его или он меня )). К счастью обошлось – он оказался джавистом, и пробовался на джавистскую вакансию.

Здесь же хочу запостить список вопросов с короткими комментариями. Все вопросы разделены на 3 группы в зависимости от уровня соискателя. Вот вопросы для самого первого уровня.

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

Ну ответ простой i |= ( i + 1 ). К слову, задачку придумал не я, я честно украл её из CBOSS’а ))

Что такое полиморфизм, наследование, инкапсуляция? Что такое динамический полиморфизм и статический? Чем они отличаются?

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

Какие функции будут добавлены в приведенном ниже классе?

	class CSomeClass{};

А вот это уже сложнее – будут созданы конструктор по-умолчанию, конструктор копирования, оператор присваивания и деструктор.

Какая здесь ошибка?

	class CSomeClass{
	public:
		int           *ptr;

         		CSomeClass( void )
         		{
                     		ptr = new int;
                     		*ptr = 1;
         		}

         		~CSomeClass()
         		{
                     		delete ptr;
         		}
  	};
  
  	void              f( CSomeClass ob )
  	{
       		std::cout<<*( ob.ptr )<<std::endl;
  	}

	void              main( int argc , char **argv )
	{
          		CSomeClass         ob;
	          	f( ob );
          		std::cout<<*( ob.ptr )<<std::endl;
	}

Неопределен конструктор копирования, поэтому при передаче объекта в функцию создается его копия. Т.е. у нас появляется 2 объекта, у которых ptr ссылается на одну область памяти. Потом для созданной копии вызывается деструктор, который удаляет общую область памяти. В итоге, когда мы пытаемся вывести значения буфера, то получаем access violation. Какая здесь ошибка?

class	CAssignableClass{
		int			x;
	public:
	
		CAssignableClass( int thex )
		{
			x = thex;
		}

		void		operator = ( const CAssignableClass &ob )
		{
			x = ob.x;
		}
	};

	int main( int argc , char *argv[] )
	{
		CAssignableClass	ob1( 1 ) , ob2( 2 ) , ob3( 3 );

		ob1 = ob2 = ob3;

		return( 0 );
	}

По уму, перегруженные операторы присваивания должны возвращать *this, поскольку в данном примере они ничего не возвращают, то во время двойного присваивания возникает ошибка компиляции. Что-то вроде «can’t assign void».


Вопросы для второго уровня.

Какая здесь ошибка?

	class		CBaseClass{
		CBaseClass( void ){}
	public:
		static CBaseClass		*Construct( void )
		{
			return( new CBaseClass() );
		}
	};

	class		CDerivedClass:public CBaseClass{
	public:
		CDerivedClass( void ){}
	};

	int main( int argc , char *argv[] )
	{
		CDerivedClass	ob;

		return( 0 );
	}

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

Какая здесь ошибка?

	class	A{
	protected:
		int 	x;
	};

	class	B: public A{};

	class	C: public A{};

	class	D: public B , C{
	public:
		D( void )
		{
			x = 0;
		}
	};

	int main( int argc , char *argv[] )
	{
		return( 0 );
	}

Ошибка возникнет во время присваивания x=0. Т.к. компилятор не будет знать какому инстансу этой переменной присваивать нулевое значение, B::A::x? Или C::A::x?

Зачем в STL нужны итераторы?

Для того чтобы был унифицированный доступ к элементам последовательности. Собственно если стандарт открыть, то там оперируют именно термином «последовательность», без указания деталей реализации этой последовательности. Это может быть вектор, стэк или очередь. Итераторы позволяют от этого всего абстрагироваться.

Чем отличается выделение памяти с помощью new и malloc?

При выделении памяти с помощью new для объекта, будет вызван конструктор этого объекта. + new является оператором и его можно перегружать для каждого класса.

Что делает следующая программа

	#include	< algorithm >
	#include	< iostream >
	#include	< vector >

	int main( int argc , char *argv[] )
	{
		std::vector< int >	v;
		v.push_back( 1 );
		v.push_back( 2 );
		v.push_back( 3 );
		v.push_back( 2 );
		v.push_back( 3 );

		v.erase( std::remove( v.begin() , v.end() , 2 ) , v.end() );

		return( 0 );
	}

Происходит удаление все элементов равных «2». Не очень быстро, зато элегантно.

Какими свойствами должен обладать объект, чтобы его можно было хранить в STL контейнере?

Должен обладать корректными конструктором копирования и оператором присваивания.


И, наконец, вопросы третьего уровня.

Что вернет функция int f( int i , int j , int k ){return(k);}, если её вызвать так:

	int i( 1 );
	std::cout<<f( ++i , ++i , ++i )<<std::cout;

Что такое undefined behaviour? Приведите примеры, когда программа начинает себя так вести.

В данном случае как раз undefined behaviour и поэтому сказать, что именно вернет функция, нельзя. Связано это с тем что порядок вычисления параметров функции неопределен стандартом. Ну а что касается примера – файл с C++ кодом должен заканчиваться символом переноса строки, иначе это ub ))

Что неправильно в данном коде:

	template< int n >class t{};
	// ...
	for( int i( 0 ) ; i < 10 ; i++ )
	{
		t< i >   ob;
	}

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

Сколько байт в памяти займет приведенный ниже класс?

	class CSomeClass{
	public:
		int			*ptr;
		virtual void		f( void ){}
	};

Во-первых, у нас есть виртуальная функция, поэтому в объекте всегда будет присутствовать указатель таблицу виртуальных функций, и занимать, как правило, 4 байта. Во-вторых, есть указатель на целое число. Он, в зависимости от платформы, может занимать 2, 4 или 8 байт 4 (то же самое относится и к указателю на таблицу виртуальных методов).

Что будет выведено на экран?

	void		f( int i )
	{
		std::cout<<i<<std::endl;
	}

	int main( int argc , char *argv[] )
	{
		f( ( 0 , 1 , 2 ) );
		_getch();
		return( 0 );
	}

Здесь обыгрывается тот факт, что в C++ запятая это оператор действующий слева направо. Поэтому в функцию f будет передано значение «2».

Расскажите про паттерны проектирования (например, абстрактная фабрика, MVC, Посетитель, Стратегия), для чего они нужны, какие из них Вам доводилось использовать на практике?

Ну, тут какого-то конкретного ответа дать нельзя. Просто этот вопрос является поводом побеседовать ))