Advanced C++ Flashcards

Learn all the nitty-gritty details of C++ specifically

1
Q

What is the difference between a class and a struct?

A

A C++ struct is simply a class where the default visibility is public. This also applies to inheritance - inheriting from a struct will always use public inheritance by default.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What does the static binding do?

A

Static is a binding that associated with the program’s lifetime, rather than the immediate scope. Assignment can be global (instantiates at program start), or local (instantiates when execution reaches that point). In either case, they are destroyed only at program end.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Consider the following code. What is the output?

int main() {
for (int i = 0; ++i; i < 4)
printNewNum();
}

void printNewNum() {
static int x = 0;
printf(“%d\n”, x++);
}

A

0
1
2
3

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is a constructor?

A

A constructor is a method called when an object is constructed. They are used to initialise the object’s variables, and have no return type. If one isn’t provided, it will be automatically generated.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

For a class ‘MyClass’, write down the signatures of the available constructor types.

A
  • Constructor - MyClass();
    • Destructor - ~MyClass();
    • Copy constructor - MyClass(const MyClass &other);
    • Copy assignment constructor - MyClass& operator=(const MyClass &other);
    • Move constructor - MyClass(const MyClass &&other);
    • Move assignment constructor - MyClass& operator=(const MyClass &&other);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is a destructor?

A

A destructor is a method that is called on object destruction, and is intended for cleaning up dynamically allocated memory or handles. As with constructors, one will be automatically provided if not given (though this will be non-virtual by default). They also lack a return type.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Consider the following code. What problem could occur when this is run, and how can it be fixed?

class A {
public:
A() { std::cout &laquo_space;“A Constructor” &laquo_space;std::endl; }
~A() { std::cout &laquo_space;“A Destructor” &laquo_space;std::endl; }
}

class B : public A {
public:
B() { std::cout &laquo_space;“B Constructor” &laquo_space;std::endl; }
~B() { std::cout &laquo_space;“B Destructor” &laquo_space;std::endl; }
}

void main() {
A *a = new B();
delete a;
}

A

When object ‘a’ is destroyed, it will call A’s destructor, but not B’s destructor as well. This can lead to memory leaks or improper cleanup.

We can fix this by making A’s destructor virtual. This will ensure that B’s destructor gets called before A’s.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Consider this class. What order are the following destroyed in?
class A, class B, class C, string printStr, int wheels, string name

class D : public A, virtual B, C {
public:
~D() {
string printStr = “Goodbye!”
printf(“%s”, printStr);
}
int wheels;
string name;
}

A

The destruction order of items in a class is as follows:

01) Class destructor body.
02) Destructors for non-static member objects are called in reverse order of declaration.
03) Destructors for inherited members are called in reverse order of declaration. Non-virtual base class destructors are always called first before any virtual ones however.

So the destruction order for the for an object D is string printStr, string name, int wheels, class A, class C, class B.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

List several circumstances in which a destructor may be called.

A

Explicit destructor call.
Local object goes out of scope.
Dynamically allocated object is deallocated with delete.
Lifetime of a temporary object ends (e.g. rvalues).
When program ends (for global and static variables).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is the diamond problem regarding inheritance? How can it be resolved?

A

The diamond problem occurs when a class inherits from two classes who themselves inherit from the same class (forming a diamond-shaped inheritance structure). What actually happens is that the intermediate classes create separate instances of the base class to inherit methods from. This leads to ambiguity over which instance to call the base method from.

This can be resolved using virtual inheritance. This forces the intermediate classes to inherit from the same instance of the base class, so only one version of the inherited method exists.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the most vexing parse? What is one way to overcome it?

A

Most vexing parse refers to ambiguity when the compiler tries to determine whether a phrase is object construction with default constructor or a function prototype with no parameters that returns class type. In the C++ standard, it is required it is interpreted in the latter way as function prototypes are prioritised over construction.

One way to overcome this is to use brace initialization, that was introduced in C++11. This unambiguously refers to constructing objects, rather than function prototypes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Describe the access modifiers available in C++.

A

Public - Accessible by any other module.
Protected - Accessible only by inheriting classes.
Private - Accessible only within class.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Describe the visibility of x/y/z to an inheriting class B if A is inherited with public, protected and private visibility respectively.

class A {
public int x;
protected int y;
private int z;
}

A

x is public, protected, private
y is protected, protected, private
z is inaccessible, inaccessible, inaccessible

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

List some of the uses of the const keyword.

A

Const variables declare that the value of that variable cannot be changed after initialisation.
If a method is declared const, it cannot change the object’s state when called (unless member variable is mutable). Const class instances can only call const methods. Const methods may also only call other const methods.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the difference between the following?

  • const int* a
  • int* const a
A

const int* a - a is a variable pointer to a constant integer
int* const a - a is a constant pointer to a variable integer

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is the difference between const and constexpr?

A

Const variables are evaluated at runtime, constexpr is evaluated at compile time. The latter allows us to make compile-time calculations and optimisations.

17
Q

What does the mutable keyword do?

A

Mutable signifies that a variable can be changed within const methods. This is usually done for variables that require changing, but aren’t part of the object’s state (e.g. locks).

18
Q

What does the typedef keyword do?

A

The typedef keyword allows you to create an alias to a module. Useful for having short developer-friendly aliases to complicated names.

19
Q

What are some of the uses of the using keyword?

A

Obtaining access to a namespace.
Obtaining access to class members.
Identical usege to typedef for aliasing.

20
Q

What is a function delegate? List some of the ways we can create one.

A

A delegate is a function wrapped in an object so it can be treated in a similar way (returned, passed to functions etc.). Some ways we can create one include:
- Function pointers
- Lambdas
- Functors (class with an overloaded () operator).
- Templates
- std::function
- std::bind

21
Q

What does it mean for a function to be inlined?

A

An inline function isn’t branched to and executed as is typically done, but instead the compiler expands every usage with its contents. This speeds up code by avoiding expensive branches, but increases executable size and compilation times. It is best used for small functions that are frequently executed.

We can declare a function inline to encourage the compiler to do so, but there’s no guarantee it will.

22
Q

What does the extern keyword do?

A

Extern extends the visibility of variables from a given header into another file. Imported headers will not have declared variables automatically visible, so we need to use extern to gain visibility of it. This is highly useful for global variables.

23
Q

What is a friend in C++?

A

A class specified as a friend in another class gives the latter access to all private and protected members of the former.

A friend function provides full access to a class taken as parameter in another class’s member function or global function.

24
Q

When would you use the explicit keyword?

A

Explicit specifier states that a constuctor forbids implicit or copy-conversions - construction must be done directly. This is only intended for single-parameter constructors.

25
Q

What does the noexcept keyword do?

A

Noexcept specifies that a given function does not throw exceptions. This allows the compiler to optimise around it.

26
Q

What does the final keyword do?

A

This is used for virtual functions to specify that it cannot be overriden by inheriting classes. It can also be used by classes to specify that it cannot be inherited from.

27
Q

What is the difference between malloc / new and free / delete?

A

Malloc / free will allocate / deallocate memory only. New / delete will do the same and call the constructor / destructor.

28
Q

What is the difference between new / delete and new[] / delete[].

A

New / delete will allocate / deallocate memory for a single object. New[] / delete[] will do so for an array. Attempting to use delete for a array will only call the destructor for the first element, potentially causing a memory leak with the remaining elements.

29
Q

What does the auto keyword do?

A

Auto allows us to automatically deduce the type of a given variable. Useful for dealing with complicated type names and prevents agains accidental type conversion. However overuse may make code less readable.

30
Q

What is decltype used for?

A

Decltype is similar to auto in that it automatically obtains the type. Decltype however works on expressions rather than types. This is useful in templated functions where the actual return type is unknown, but can be determined at compile time. For example:

template<class A, class B>
void MultiplyAB(A a, B b, decltype(a*b)& output) {
output = a * b;
}

31
Q

What is typeid used for?

A

Typeid obtains information about a type at runtime. One use is to obtain its name.

32
Q

What is operator overloading in C++? Are there any we cannot overload?

A

Operator overloading creates a function to define new behaviour of when that operator is used with that object. For example, overloading + operator:

Box operator+(const Box& b) {
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}

We cannot overload the ::, .*, . or ?: operators.

33
Q

What does the volatile keyword do?

A

Volatile tells the compiler to avoid optimising a variable by caching it as its value can change unexpectedly outside the program. It forces the value to be read from memory every time.

34
Q

For two’s complement signed integers, how do we turn a positive number into a negative number?

A

Take all other bits of the number except top, invert and add 1.

35
Q

List the different casts available in C++ and describe how they work.

A

Static - compile-time, performs implicit conversions between types or call conversion constructors.
Dynamic - runtime, attempts to cast from a base class to a derived class.
Const - casts from const to non-const, useful for modifying member variables in const functions and passing const variables to non-const functions. Attempting to use on initially const variables however is undefined behavior.
Reinterpet - casts to any type, often with raw byte data.
C-style - attempts static, const and reinterpret cast. Unsafe as dynamic isn’t considered.

36
Q

Why use smart pointers over regular pointer types?

A

Smart pointers address some of the issues facing regular pointers and help enforce RAII semantics for memory management.