C++ Pro Flashcards
Q: Give the type for a function pointer to a member function of Foo that returns int and takes a char and float parameters.
A: int (Foo::*)(char,float)
Q: What are some ways try / catch / throw can improve software quality?
A: By eliminating one of the reasons for if statements. The commonly used alternative to try / catch / throw is to return a return code (sometimes called an error code) that the caller explicitly tests via some conditional statement such as if. For example, printf(), scanf() and malloc() work this way: the caller is supposed to test the return value to see if the function succeeded. Although the return code technique is sometimes the most appropriate error handling technique, if statements can be the source of many bugs.
throw also forces a run-time check, if only trivially, because an uncaught exception will generate a message to a user, hopefully containing information about the type of fault. A return code, on the other hand, can be ignored causing a crash with no useful message. The source of the fault must then be traced backwards from the crash point, which can be far away in the code.
Q: What is the assignment operator?
A: The default assignment operator handles assigning one object to another of the same class. Member to member copy is done via shallow copy.
Q: Can a copy constructor accept an object of the same class as parameter, instead of reference of the object?
A: No. It is specified in the definition of the copy constructor itself. It should generate an error if a programmer specifies a copy constructor with a first argument that is an object and not a reference.
Q: What is a class?
A: A class is an expanded concept of a data structure: instead of holding only data, it can hold both data and functions.
Q: How do you handle a constructor that fails?
A: throw an exception. Constructors don’t have a return type, so it’s not possible to use return codes. The best way to signal constructor failure is therefore to throw an exception.
Q: How can I provide input for my class Fred?
A: Use operator overloading to provide a friend right-shift operator, operator>>. This is similar to the output operator, except the parameter doesn’t have a const: “Fred&” rather than “const Fred&”.
class Fred
{
public:
friend std::istream& operator>> (std::istream& i, Fred& fred);
private:
int i_; // Just for illustration
};
std::istream& operator>> (std::istream& i, Fred& fred)
{
return i >> fred.i_;
}
int main(){
Fred f;
std::cout << “Enter a Fred object: “;
std::cin >> f;
}
Note that operator>> returns the stream. This is so the input operations can be cascaded and/or used in a while loop or if statement.
Q: What are some advantages/disadvantages of using friend functions?
A: They provide a degree of freedom in the interface design options. Member functions and friend functions are equally privileged (100% vested). The major difference is that a friend function is called like f(x), while a member function is called like x.f(). Thus the ability to choose between member functions (x.f()) and friend functions (f(x)) allows a designer to select the syntax that is deemed most readable, which lowers maintenance costs.
The major disadvantage of friend functions is that they require an extra line of code when you want dynamic binding. To get the effect of a virtual friend, the friend function should call a hidden (usually protected) virtual member function. This is called the Virtual Friend Function Idiom.
Q: Should constructors use “initialization lists” or “assignment”?
A: Initialization lists. In fact, as a rule constructors should initialize all member objects in the initialization list. Every rule has exceptions. This might happen when your class has two constructors that need to initialize this object’s data members in different orders. Or it might happen when two data members are self-referential. Or when a data- member needs a reference to this object, and you want to avoid a compiler warning about using the this keyword prior to the open curly brace of the constructor.
Q: What is the down side with runtime type identification (RTTI)?
A: The run time type identification comes with a performance penalty. Both dynamic_cast and typeid require RTTI to be maintained by the run time environment. Compiler support for RTTI may be optional.
int main () { int \* a,b; a=0; b=0; if (typeid(a) != typeid(b)) { cout \<\< "a and b are of different types:\n"; cout \<\< "a is: " \<\< typeid(a).name() \<\< '\n'; cout \<\< "b is: " \<\< typeid(b).name() \<\< '\n'; } return 0; }
Q: When you write a derived class’s destructor, do you need to explicitly call the destructor for my base class?
A: No. You never need to explicitly call a destructor (except with placement new).
A derived class’s destructor (whether or not you explicitly define one) automagically invokes the destructors for base class subobjects. Base classes are destructed after member objects.
In the event of multiple inheritance, direct base classes are destructed in the reverse order of their appearance in the inheritance list.
Order dependencies with virtual inheritance are trickier. If you are relying on order dependencies in a virtual inheritance hierarchy, you’ll need a lot more information than we have here.
Q: What is copy constructor?
A: Constructor that initializes its object member variables ( byshallow copying) with another object of the same class. If you don’t implement one in your class then thecompiler implements one for you. Dor example:
(a) Boo Obj1(10); // calling Boo constructor
(b) Boo Obj2(Obj1); // calling boo copy constructor
(c) Boo Obj2 = Obj1;// calling boo copy constructor
Q: What is multiple inheritance(virtual inheritance)? What are its advantages and disadvantages?
A: Multiple Inheritance is the process whereby a child can be derived from more than one parent class. The advantage of multiple inheritance is that it allows a class to inherit the functionality of more than one base class thus allowing for modeling of complex relationships.The disadvantage of multiple inheritance is that it can lead to a lot of confusion(ambiguity) when two base classes implement a method with the same name.
Q: Can you think of a situation where your program would crash without reaching the breakpoint which you set at the beginning of main()?
A: C++ allows for dynamic initialization of global variables before main() is invoked. It is possible that initialization of global will invoke some function. If this function crashes the crash will occur before main() is entered.
Q: How do I convert a number to a string?
A: The simplest way is to use a stringstream:
inline std::string stringify(double x)
{
std::ostringstream o;
if (!(o << x))
throw BadConversion(“stringify(double)”);
return o.str();
}
Q: Should a class declare a member function or a friend function?
A: Use a member when you can, and a friend when you have to. Sometimes friends are syntactically better (e.g., in class Fred, friend functions allow the Fred parameter to be second, while members require it to be first). Another good use of friend functions are the binary infix arithmetic operators. E.g., aComplex + aComplex should be defined as a friend rather than a member if you want to allow aFloat + aComplex as well (member functions don’t allow promotion of the left hand argument, since that would change the class of the object that is the recipient of the member function invocation). In other cases, choose a member function over a friend function.
Q: What are the differences between a C++ struct and C++ class?
A: The default member and base class access specifiers are different. This is one of the commonly misunderstood aspects of C++. Believe it or not, many programmers think that a C++ struct is just like a C struct, while a C++ class has inheritance, access specifes, member functions, overloaded operators, and so on. Actually, the C++ struct has all the features of the class. The only differences are that a struct defaults to public member access and public base class inheritance, and a class defaults to the private access specified and private base-class inheritance.
Q: How do you wrap a new Foo() in a smart pointer?
A:
std::auto_ptr z (new Foo());
Q: What is a const_cast?
A: It changes the constness of any pointer or reference, so converts from const to not-const, or from not-const to const.
Q: How many ways are there to initialize an int with a constant?
A: Two that I know of:
(a) int foo = 123;
(b) int bar(123);
Q: Do I need to check for NULL before delete p?
A: No. The C++ language guarantees that delete p will do nothing if p is equal to NULL. Since you might get the test backwards, and since most testing methodologies force you to explicitly test every branch point, you should not put in the redundant if test.
Q: How do I allocate / unallocate an array of things?
A: Use p = new T[n] and delete[] p:
Any time you allocate an array of objects via new (usually with the [n] in the new expression), you must use [] in the delete statement. This syntax is necessary because there is no syntactic difference between a pointer to a thing and a pointer to an array of things (something we inherited from C).
Q: What are storage qualifiers in C++ ?
A: They are:
const: Indicates that memory once initialized, should not be altered by a program.
volatile: Indicates that the value in the memory location can be altered even though nothing in the program code modifies the contents. Forces compiler to generate code to read that storage every time it is used, even if no code has written to the location.
mutable: Indicates that particular member of a structure or class can be altered even if a particular structure variable, class, or class member function is constant.
Q: What are the benefits of operator overloading?
A: By overloading standard operators on a class, you can exploit the intuition of the users of that class. This lets users program in the language of the problem domain rather than in the language of the machine.The ultimate goal is to reduce both the learning curve and the defect rate.
Q: What is an inline function?
A: The inline keyword tells the compiler to substitute the code within the function definition for every instance of a function call. However, substitution occurs only at the compiler’s discretion.
Q: After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?
A: Short answer: Magic. Long answer: The run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the pointer, p. There are two popular techniques that do this. Both these techniques are in use by commercial-grade compilers, both have tradeoffs, and neither is perfect. These techniques are:Over-allocate the array and put n just to the left of the first Fred object. Use an associative array with p as the key and n as the value.
Q: What are C++ storage classes?
A:
auto: The default. Variables are automatically created and initialized when they are defined and are destroyed at the end of the block containing their definition. They are not visible outside that block.
register: a type of auto variable. A suggestion to the compiler to use a CPU register for performance.
static: A variable that is known only in the function that contains its definition but is never destroyed and retains its value between calls to that function. It exists from the time the program begins execution.
extern: A static variable whose definition and placement is determined when all object and library modules are combined (linked) to form the executable code file. It can be visible outside the file where it is defined.
Q: What is stack unwinding?
A: It is a process during exception handling when the destructor is called for all local objects in the stack between the place where the exception was thrown and where it is caught.
Q: What operators can/cannot be overloaded?
A: Most can be overloaded. The only C operators that can’t be are . and ?: (and sizeof, which is technically an operator).
C++ adds a few of its own operators, most of which can be overloaded except :: and .*.
Here’s an example of the subscript operator (it returns a reference).
class Array {
public:
int& operator[] (unsigned i) { if (i > 99) error(); return data[i]; }
private:
int data[100];
};
int main()
{
Array a;
a[10] = 42;
a[12] += a[13];
…
}
Q: What is a Pure Virtual Function?
A: virtual foo() = 0;It is an error to define a pure virtual function in the class where it was declared or to instantiate the abstract class. Subclasses may define the function, otherwise it remains a pure virtual function in the subclass as well.
Q: How does free know the size of memory to be deleted.?int *i = (int *)malloc(12); followed by free(i); how did free function call know how much of memory to delete?
A: It depends on the implementation, but there is usually a malloc header added to all the memory allocated through malloc. On Linux it’s 4 bytes of memory preceding the memory returned to you, which contains the number of bytes allocated + 4(itself). So when you say,int *i = (int *)malloc(12); it allocates 16 bytes.
Q: Can you drop the [] when deleteing array of some built-in type (char, int, etc)?
A: No! Sometimes programmers think that the [] in the delete[] p only exists so the compiler will call the appropriate destructors for all elements in the array. Because of this reasoning, they assume that an array of some built-in type such as char or int can be deleted without the []. But this is wrong, and it can cause a disaster at runtime. In particular, the code that’s called for delete p is operator delete(void*), but the code that’s called for delete[] p is operator delete. The default behavior for the latter is to call the former, but users are allowed to replace the latter with a different behavior (in which case they would normally also replace the corresponding new code in operator new). If they replaced the delete[] code so it wasn’t compatible with the delete code, and you called the wrong one (i.e., if you said delete p rather than delete[] p), you could end up with a disaster at runtime.
Q: What are the access privileges in C++? What is the default access level?
A: The access privileges in C++ are private, public and protected. The default access level assigned to members of a class is private. Private members of a class are accessible only within the class and by friends of the class. Protected members are accessible by the class itself and its sub-classes. Public members of a class can be accessed by anyone.
Q: When should you use references, and when should you use pointers?
A: Use references when you can, and pointers when you have to. References are usually preferred over pointers whenever you don’t need “reseating”. This usually means that references are most useful in a class’s public interface. References typically appear on the skin of an object, and pointers on the inside.
The exception to the above is where a function’s parameter or return value needs a “sentinel” reference, a special reference value that does not refer to an object.
Additionally, pointers are useful when you need one variable to indicate varying objects over its lifetime. Permanent relationships could be modeled with a reference, but a more dynamic relationship can use a pointer.
Q: What are some examples of operator overloading?
A: Here are a few of the many examples of operator overloading:
myString + yourString might concatenate two std::string objects
myDate++ might increment a Date object
a * b might multiply two Number objects
a[i] might access an element of an Array
objectx = *p might dereference a “smart pointer” that “points” to a disk record
Q: Do I need to check for NULL after p = new Fred()?
A: No. It turns out to be a real pain to always write explicit NULL tests after every new allocation. Code like the following is very tedious:
Fred\* p = new Fred(); if (p == NULL) throw std::bad\_alloc();
Take heart. In C++, if the runtime system cannot allocate sizeof(Fred) bytes of memory during p = new Fred(), a std::bad_alloc exception will be thrown. Unlike malloc(), new never returns NULL!
Q: Why can’t you open a file in a different directory such as “..\test.dat”?
A: Because “\t” is a tab character.You should use forward slashes in your filenames, even on operating systems that use backslashes (DOS, Windows, OS/2, etc.).
Remember, the backslash (“") is used in string literals to create special characters: “\n” is a newline, “\b” is a backspace, and “ “ is a tab, “\a” is an “alert”, “\v” is a vertical-tab, etc.
Use “/”, even on systems that use a “" as the directory separator. This works because the library routines on these operating systems handle “/” and “" interchangeably.
Of course you could use “\” instead, but it is hard to read and easy to miss one “".
Q: Is the default constructor for Fred always Fred::Fred()?
A: No. A “default constructor” is a constructor that can be called with no arguments.
One example of this is a constructor that takes no parameters. Another example of a “default constructor” is one that can take arguments, provided they are given default values:
class Fred { public:Fred(int i=3, int j=5); // Default constructor: can be called with no args
Q: Is there any difference between List x; and List x();?
A: A big difference! Suppose that List is the name of some class. Then function f() declares a local List object called x:
void f() { List x; // Local object named x (of class List) ...}
But function g() declares a function called x() that returns a List:
void g() { List x(); // Function named x (that returns a List) ...}
Q: In the following block, what gets cleaned up at the end of scope?
{
Thing* t = new Thing;
}
A: t gets deleted (just the pointer), but the instance of Thing does not. This may be a memory leak.
Q: Can you overload operator== so it lets you compare two char[] using a string comparison?
A: No: at least one operand of any overloaded operator must be of some user-defined type (most of the time that means a class).But even if C++ allowed you to do this, which it doesn’t, you wouldn’t want to do it anyway since you really should be using a std::string-like class rather than an array of char in the first place since arrays are evil.
Q: What is Memory alignment?
A: The term alignment primarily means the tendency of an address pointer value to be a multiple of some power of two. So a pointer with two byte alignment has a zero in the least significant bit. And a pointer with four byte alignment has a zero in both the two least significant bits. And so on. More alignment means a longer sequence of zero bits in the lowest bits of a pointer.
Q: What are some guidelines / “rules of thumb” for overloading operators?
A: Here are a few guidelines / rules of thumb:
If you define arithmetic operators, maintain the usual arithmetic identities. For example, if your class defines x + y and x - y, then x + y - y ought to return an object that is behaviorally equivalent to x. That means the two objects should ideally act like they have the same state.
You should provide mixed-mode arithmetic operators only when they make logical sense to users. For example, it makes sense to add a duration (say 35 days) to a date (say July 4, 1776), so you might define date + duration to return a Date. Similarly date - duration could also return a Date. But duration - date does not make sense at the conceptual level (what does it mean to subtract July 4, 1776 from 35 days?) so you should not define that operator.
If you provide constructive operators, they should return their result by value. For example, x + y should return its result by value.
If you provide constructive operators, they should not change their operands. For example, x + y should not change x. For some crazy reason, programmers often define x + y to be logically the same as x += y because the latter is faster. But remember, your users expect x + y to make a copy.
If you provide constructive operators, they should allow promotion of the left-hand operand. For example, if your class Fraction supports promotion from int to Fraction (via the non-explicit ctor Fraction::Fraction(int)), and if you allow x - y for two Fraction objects, you should also allow 42 - y. In practice that simply means that your operator-() should not be a member function of Fraction. Typically you will make it a friend, if for no other reason than to force it into the public: part of the class, but even if it is not a friend, it should not be a member.
In general, your operator should change its operand(s) if and only if the operands get changed when you apply the same operator to intrinsic types. x == y and x << y should not change either operand.
Q: What is static_cast?
A: static_cast converts from a pointer to a base class to a pointer to its derived class, but does not perform type-safety checking.
Q: What is a conversion operator?
A: A class can have a public method for specific data type conversions. For example:
class Boo{ double value; public: Boo(int i ); operator double() { return value; }};
Boo BooObject;
double i = BooObject;
Give the type for a function pointer to a static member function of Foo that returns int and takes char and float parameters.
A: int (*)(char,float)
Q: Can inline functions have a recursion?
A: No. Syntax wise it is allowed. But then the function is no longer Inline. As the compiler will never know how deep the recursion is at compilation time.
Q: What is the default constructor?
A: A constructor with no arguments or one where all the arguments have default values.
Q: What’s the order that objects in an array are destructed?
A: In reverse order of construction: First constructed, last destructed.In the following example, the order for destructors will be a[9], a[8], …, a[1], a[0]:
void userCode() {Fred a[10];}
Q: How can I make it so keys pressed by users are not echoed on the screen?
A: This is not a standard C++ feature. C++ doesn’t even require your system to have a keyboard or a screen. That means every operating system and vendor does it somewhat differently. Please read the documentation that came with your compiler for details on your particular installation.
Q: Show a const object calling a const member.
A:
class Foo { int bar() const { return 99; }}
main…
const Foo f;
f.bar();
Q: What happens when a derived-class object is created and destroyed?
A: Space is allocated (on the stack or the heap) for the full object (that is, enough space to store the data members inherited from the base class plus the data members defined in the derived class). The base class’s constructor is called to initialize the data members inherited from the base class. The derived class’s constructor is then called to initialize the data members added in the derived class. The derived-class object is then usable.
When the object is destroyed (goes out of scope or is deleted) the derived class’s destructor is called on the object first. Then the base class’s destructor is called on the object. Finally the allocated space for the full object is reclaimed
Q: What is the difference between “new” and “operator new” ?
A: operator new (or new[]) allows the class designer to customize new(). Declaration looks like this:
class Myclass { public: void\* operator new(size\_t); void operator delete(void\*); };
One can implement new using malloc. The compiler takes care of creating the vtable and calling the constructor, so that isn’t done in the operator.
You can also call operator new like this:
::operator new(sizeof(Foo))
This calls the global operator new, which only allocates memory.
Q: What is a friend class?
A: A class that grants friend status to another class gives that class access rights to all private and protected members.
Q: How do you find the size of an integer data type with out using sizeof() function?
A:
int *i ;
int *j = i + 1;
cout << “ size of an integer variable i = “ << (int)j - (int)i << endl;
Q: Do friends violate encapsulation?
A: Not f they’re used properly, they enhance encapsulation.You often need to split a class in half when the two halves will have different numbers of instances or different lifetimes. In these cases, the two halves usually need direct access to each other (the two halves used to be in the same class, so you haven’t increased the amount of code that needs direct access to a data structure; you’ve simply reshuffled the code into two classes instead of one). The safest way to implement this is to make the two halves friends of each other.
Q: Explain the statement, “friendship isn’t inherited, transitive, or reciprocal”?
A:
Inherited: Just because I grant you friendship access to me doesn’t automatically grant your kids access to me
Transitive: Just because I grant you friendship access to me doesn’t automatically grant your friends access to me
Transitive: Just because I grant you friendship access to me doesn’t automatically grant me access to you