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: 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: 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: 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 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: 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: 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: 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 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: 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: 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 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: 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: 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: 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: 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: 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 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: 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: 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: 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: 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;
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.
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: 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: 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: 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: 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
Q: What is a functor? Give an example of a C++ functor by overloading the function call ( ) operator.
A: Functors, or function objects, are objects that can be called like functions. They can be useful, for example, as callback functions. They have the advantage over functions in their power to retain state.
class Multiplier {
public:
Multiplier(int m): multiplier(m) {}
int operator()(int x) { return multiplier * x; }
private:
int multiplier;
};
Multiplier m(5); cout \<\< m(4) \<\< endl;
Q: What should I catch?
A: In keeping with the C++ tradition of “there’s more than one way to do that” (translation: “give programmers options and tradeoffs so they can decide what’s best for them in their situation”), C++ allows you a variety of options for catching.You can catch by value.You can catch by reference.You can catch by pointer.
In fact, you have all the flexibility that you have in declaring function parameters, and the rules for whether a particular exception matches (i.e., will be caught by) a particular catch clause are almost exactly the same as the rules for parameter compatibility when calling a function.
Given all this flexibility, how do you decide what to catch? Simple: unless there’s a good reason not to, catch by reference. Avoid catching by value, since that causes a copy to be made and the copy can have different behavior from what was thrown. Only under very special circumstances should you catch by pointer.
Q: What does it mean to declare a…
(a) member function as virtual?
(b) member variable as static?
(c) function as static?
(d) destructor as static?
A:
(a) C++ virtual function is a member function of a class, whose functionality can be over- ridden in its derived classes. Non-virtual member functions are resolved at compile time, virtual member functions are resolved at run time.
(b) The static keyword allows a variable to maintain its value among different function calls. This is possible because, when the static variable is declared, the compiler uses a separate memory area to store it.
(c) A static member function can access only static member data, static member functions and data and functions outside the class. A static member function can be called even when a class is not instantiated. A static member function cannot be declared virtual. A static member function cannot have access to the ‘this’ pointer of the class.
(d) There is no such thing, unless “static destructor” means a static member function of the class that accepts a pointer to an object of that class that is to be destroyed.
Q: Why should I use new instead of trustworthy old malloc()?
A: Constructors/destructors, type safety, overridability.
Constructors/destructors: unlike malloc(sizeof(Fred)), new Fred() calls Fred’s constructor. Similarly, delete p calls *p’s destructor.
Type safety: malloc() returns a void* which isn’t type safe. new Fred() returns a pointer of the right type (a Fred*).
Overridability: new is an operator that can be overridden by a class, while malloc() is not overridable on a per-class basis.
Q: How can I provide printing for my class Fred?
include
A: Use operator overloading to provide a friend left-shift operator.
class Fred {
public:
friend std::ostream& operator<< (std::ostream& o, Fred const& fred);
…
private:
int i_; // Just for illustration
};
std::ostream& operator<< (std::ostream& o, Fred const& fred)
{
return o << fred.i_;
}
int main()
{
Fred f;
std::cout << “My Fred object: “ << f << “\n”;
…
}
We use a non-member function (a friend in this case) since the Fred object is the right-hand operand of the << operator.
Q: Is it legal for a member function to say “delete this”?
A: As long as you’re careful, it’s OK for an object to commit suicide (delete this). Here’s how I define “careful”:
You must be absolutely 100% positive sure that this object was allocated via new (not by new[], nor by placement new, nor a local object on the stack, nor a global, nor a member of another object; but by plain ordinary new).
You must also be absolutely 100% positive sure that your member function will be the last member function invoked on this object.
Q: What is a Polymorphic Class?
A: A polymorphic class contains at least one virtual method. C++ saves resources by create vtables only for polymorphic classes.
Q: What is a smart pointer?
A: A smart pointer is a C++ class that mimics a regular pointer in syntax and some semantics, but it does more.
Because smart pointers to different types of objects tend to have a lot of code in common, almost all good-quality smart pointers in existence are templated by the pointee type.
This is the mantra of smart pointers: You can replace pointer definitions with smart pointer definitions without incurring major changes to your application’s code. You thus get extra goodies with ease. Minimizing code changes is very appealing and vital for getting large applications to use smart pointers.
Q: What is Overriding?
A: To override a method, a subclass of the class that originally declared the method must declare a method with the same name, return type (or a subclass of that return type), and same parameter list.The definition of the method overriding is:· Must have same method name.· Must have same data type.· Must have same argument list. Overriding a method means that replacing a method functionality in child class.
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: Is there any problem with the following :
char*a=NULL;
char& p = *a;?
A: The result is undefined. You should never do this. A reference must always refer to some object.