This set of questions came from a prominent gaming company. As you can see, the answers are not given (the interviews are typically conducted by senior developers), but there’s a set of notes with common mistakes to avoid.
- Explain which of the following declarations will compile and what will be constant - a pointer or the value pointed at:
- const char *
- char const *
- char * const
Note: Ask the candidate whether the first declaration is pointing to a string or a single character. Both explanations are correct, but if he says that it’s a single character pointer, ask why a whole string is initialized as char* in C++. If he says this is a string declaration, ask him to declare a pointer to a single character. Competent candidates should not have problems pointing out why const char* can be both a character and a string declaration, incompetent ones will come up with invalid reasons.
- You’re given a simple code for the class BankCustomer. Write the following functions:
- Copy constructor
- = operator overload
- == operator overload
- + operator overload (customers’ balances should be added up, as an example of joint account between husband and wife)
Note:Anyone confusing assignment and equality operators should be dismissed from the interview. The applicant might make a mistake of passing by value, not by reference. The candidate might also want to return a pointer, not a new object, from the addition operator. Slightly hint that you’d like the value to be changed outside the function, too, in the first case. Ask him whether the statement customer3 = customer1 + customer2 would work in the second case.
- What problems might the following macro bring to the application?
#define sq(x) x*x
- Consider the following struct declarations:
struct A { A(){ cout << "A"; } }; struct B { B(){ cout << "B"; } }; struct C { C(){ cout << "C"; } }; struct D { D(){ cout << "D"; } }; struct E : D { E(){ cout << "E"; } }; struct F : A, B { C c; D d; E e; F() : B(), A(),d(),c(),e() { cout << "F"; } };What constructors will be called when an instance of F is initialized? Produce the program output when this happens.
- Anything wrong with this code?
T *p = new T[10]; delete p;
Note: Incorrect replies: “No, everything is correct”, “Only the first element of the array will be deleted”, “The entire array will be deleted, but only the first element destructor will be called”.
- Anything wrong with this code?
T *p = 0; delete p;
Note: Typical wrong answer: Yes, the program will crash in an attempt to delete a null pointer. The candidate does not understand pointers. A very smart candidate will ask whether delete is overloaded for the class T.
- Explain virtual inheritance. Draw the diagram explaining the initialization of the base class when virtual inheritance is used.
Note: Typical mistake for applicant is to draw an inheritance diagram, where a single base class is inherited with virtual methods. Explain to the candidate that this is not virtual inheritance. Ask them for the classic definition of virtual inheritance. Such question might be too complex for a beginning or even intermediate developer, but any applicant with advanced C++ experience should be somewhat familiar with the concept, even though he’ll probably say he’d avoid using it in a real project. Moreover, even the experienced developers, who know about virtual inheritance, cannot coherently explain the initialization process. If you find a candidate that knows both the concept and the initialization process well, he’s hired. - What’s potentially wrong with the following code?
long value; //some stuff value &= 0xFFFF;
Note: Hint to the candidate about the base platform they’re developing for. If the person still doesn’t find anything wrong with the code, they are not experienced with C++.
- What does the following code do and why would anyone write something like that?
void send (int *to, int * from, int count) { int n = (count + 7) / 8; switch ( count % 8) { case 0: do { *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while ( --n > 0 ); } } - In the H file you see the following declaration:
class Foo { void Bar( void ) const ; };Tell me all you know about the Bar() function.
23 Comments on C++ gamedev interview questions
Heres a question I faced. What are templates and can templates be used in C#?
/*This is regarding question 5. I compiled and executed the following program and it worked. So what is wrong with it? */
# include
class T {int i;};
main()
{
T *p = new T[10];
delete p;
}
rachna:
The issue with #5 is that you *must* always call array delete when deleting an array (in this case, an array to T’s. The proper code looks like this:
class T {int i;};
main()
{
T *p = new T[10];
delete [] p;
}
BTW, my best advice for C++ interviews is to read Scott Meyers’ books.
T *p = 0;
delete p;
Perfectly valid (if stupid) code. The C++ standard says its legal to delete null pointers, and its a noop.
What is single ton effect.Can i use this function to create the object at restrict times?
#define sq(x) x*x
b = 5;
a = sq(b++); // expands to b++ * b++
Answer is 30 (5*6) if sq is a macro.
Answer is 25 if sq was a function.
This is known as Duff’s device, from the C++ book,
it speeds up copying of a string by pipelining
8 chars at a time.
void send (int *to, int * from, int count)
{
int n = (count + 7) / 8;
switch ( count % 8)
{
case 0: do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while ( –n > 0 );
}
}
The constant 0xffff should be written as 0×0ffffL with the suffix L
to indicate it is long, otherwise it will be sign extended, please
compile and confirm.
long value;
//some stuff
value &= 0xFFFF;
Easy way to remember object of ‘const’, is that it applies to the
immediate object to its right:
const char* p; //mutable pointer to constant char
char const*p; // constant pointer to mutable char, same as next
char* const p; // constant pointer to mutable char
const char* const p; // const pointer to const char
Thank you very much. Very useful site. I’ll tell to all my friends about this site
Shafi, that is not correct. “const char * p” == “char const * p” (i.e., the “char” is const”). Try it. The correct “easy way to remember” is that const makes the type immediately following on the LEFT constant.
Another way to remember is to recall that we are declaring a pointer and that a * will be used later to dereference (access) the variable:
Therefore, if the const is on the left of the *, the const acts (through the *) on the dereferenced variable (i.e. the variable itself is constant), otherwise if the const is on the right of the * the const acts on the pointer itself (the pointer is constant).
In other words the const is acting in the same way that we would try to use the pointer/variable.
see the explaination at: http://www.possibility.com/Cpp/const.html
const int x; // constant int
x = 2; // illegal - can’t modify x
const int* pX; // changeable pointer to constant int
*pX = 3; // illegal - can’t use pX to modify an int
pX = &someOtherIntVar; // legal - pX can point somewhere else
int* const pY; // constant pointer to changeable int
*pY = 4; // legal - can use pY to modify an int
pY = &someOtherIntVar; // illegal - can’t make pY point anywhere else
const int* const pZ; // const pointer to const int
*pZ = 5; // illegal - can’t use pZ to modify an int
pZ = &someOtherIntVar; // illegal - can’t make pZ point anywhere else
#define sq(x) x*x
b = 5;
a = sq(b++); // expands to b++ * b++
Answer is 30 (5*6) if sq is a macro.
Answer is 25 if sq was a function.
NOT really. The result depends on the compiler (I did not check what the standard says, I’ll do).
On Solaris, AIX, GCC, aCC (HP-UX) the result is 30 (sorry I made a typo in my previous remark)
#define sq(x) x*x
the ++ operator is not a good example of why this is a bad macro. It’s simply an example of how not to use a macro.
If you must use a macro, you should always enclose the passed argument in parentheses. Otherwise, the dumb macro will give you an unexpected result - for example:
int a = 1;
int b = 2;
cout
(last comment cut off due to inappropriate use of an html tag identifier following cout )
int a = 1;
int b = 2;
printf(”%d”, sq(a+b));// 1+2*1+2=1+2+2=5, not 9.
#define sq(x) (x)*(x) fixes this problem.
Q4: When an instance of F is initialized, the program output is:ABCDDEF
explain about sub class in c++.
#define sq(x) x*x
Should have been written like this instead:
#define sq(x) (x) * (x)
Before satisfying yourself that your answer to a question regarding macros is complete, remind yourself that a macro is really just a fancy text replacement feature, and consider what happens if it might be used on any of the following:
1. An arithmetic expression
2. function call
3. some syntactically correct statment
In the case of arithmetic expressions, the order of operations must be accounted for:
sq( 10 + 5 * 6 ) is going to become
10 + 5 * 6 * 10 + 5 * 6
As some have hinted at with the increment and decrement operators, a function call might have side-effects that end up giving you results you weren’t expecting:
sq( MyFunction( ‘A’ ) ) is going to become
MyFunction( ‘A’ ) * MyFunction( ‘A’ )
If there is a chance that the function won’t return the same value both times, then you’re not going to end up with a square, right?
The best form for any kind of macro is to include all of its parameters in parenthesis. This preserves the order of operations, and also preserves other syntactic rules.
These are some tough questions and this is an excellent resource for developers as well as interviewers! I’m a very experienced C developer, I’ve been implementing in C++ for over 5 years, and I had a lot of trouble with the questions!
1. I found this page through Google in an attempt to determine whether “const char*” and “char const*” are identical. I now understand better how to use ‘const’ in declarations. Most C/C++ developers I know are weak on this subject and avoid ‘const’ pointer declarations altogether.
2. I know what the issues are here: passing the parameter(s) correctly (usually by ‘const’ reference) and returning the correct type in the correct manner. But when I do implement any of these operators, which is not often, I always look for a working example to use as a model. I don’t try to memorize the syntax of features I don’t use every day; I need to save some space in my memory for domain-specific knowledge that I can’t look up.
3. This is an easy one for any experienced C developer. In C++, there’s no reason to use a macro for this anyway; use an inline template function instead. This will work for any type that the compiler can find a multiplication operator for, and, when it fails, an error message will be given instead of code that compiles but doesn’t work correctly.
4. Wow! I never knew that I was supposed to memorize the initialization-order rules! In my opinion, if the semantic correctness of a class depends on the order in which its base classes and member objects are initialized, then something is fundamentally wrong with the design of the class hierarchy.
5. I know that the array delete should be called here. I also know from experience that the scalar delete will work (in VC++) if the class has no destructor (an array of chars or ints, for example.) I always assumed that, if the class has a destructor, it would be called for the first element of the array when a scalar delete is used, but the notes indicate otherwise. Since this is an easy mistake to make, shouldn’t the C++ compiler prohibit using a scalar delete on an array or an array delete on a scalar?
6. I knew this one because I do it all the time. In practice, there are statements between the declaration and the ‘delete’ that may or may not assign a ‘new’ T to p, depending on conditional statements.
7. I didn’t know about virtual inheritance and avoided multiple inheritance largely because of the problem that virtual inheritance solves. I have learned something valuable from this question.
8. I have seen this mistake before, but the VC++ .NET 2003 compiler gives the expected result for the example given. I think that the compiler should give the expected result (not sign-extending the constant) if ‘value’ is unsigned and warn that the result may not be what the developer intends if ‘value’ is signed.
9. I agree that this looks like a way to speed up the copy by reducing the loop overhead. I didn’t even know starting a ‘do’ block in one ‘case’ statement and ending it in another would work or give the same results using different compilers. I wouldn’t want to work with someone who wrote code like that; I’d spend forever trying to understand his/her code. It looks like it should be possible to place the loop around the ’switch’ statement instead of inside it. The remainder would need to be put in a variable and that variable set to 8 after the first loop iteration, but it would improve readability greatly. The use of “count % 8″ looks incorrect to me: I think the procedure will attempt to copy 8 characters if ‘count’ is zero.
10. Bar() doesn’t have any parameters, nor does it return a value, so, if it does anything useful, it must modify something in the Foo class object itself. (If Bar() only modifies variables outside the class, why would it be defined as a method of the class?) However, it is declared ‘const’, meaning that it shouldn’t modify anything in the class that would affect other methods of the class. It probably modifies something like performance- or statistics-gathering properties of the class that users of the class are unaware of; these members should be declared ‘mutable’ to keep things clear.
Alex:
#define sq(x) (x)*(x) does not fix the problem:
int a = 10;
int b = 200 / sq(a);
It becomes:
int b = 200 / (10) * (10); // answer becomes 200 not 2
You need:
#define sq(x) ((x) * (x)) to fix it.
5. The class might have its own operator delete[]()?
for question 1:
“int* const pY” is the same as “int const *pY” as constant pointer to changeable int.
for question 2:
class BankCustomer
{
public:
BankCustomer(){ _balance=0;};
~BankCustomer();
float getBalance(){ return _balance;}
void setBalance(float b){_balance=b;}
bool operator= =(const BankCustomer &rhs)
{
if (_balance = = rhs->getBalance())
return 1;
else
return 0;
};
void operator=(const BankCustomer &rhs)
{
rhs->setBalance(_balance); };
void operator+(const BankCustomer &rhs)
{
_balance=_balance+rhs->getBalance();};
Private:
float _balances;
};