CPA-21-02 Sample Questions

CPA-21-02 Sample Questions & Answers

Object-oriented principles, class definitions, constructors and destructors carry the heaviest weight, alongside pointer declarations and arithmetic, overloaded function basics, exception handling in control-flow statements, and ternary, binary and unary operators.

Launch the full CPA-21-02 simulator →

Showing 10 of 20 free samples.

  1. Question 1Beginner

    Classes & Namespaces · Compiler-generated special member functions

    True or False: In C++, if a class has a user-defined destructor, the compiler will no longer implicitly generate a default constructor.

    Show answer & explanation

    Correct answer: B

    This statement is false. The presence of a user-defined destructor does not prevent the compiler from generating a default constructor. However, if a user declares any constructor (e.g., a copy constructor or a constructor with parameters), the compiler will then refrain from generating the default constructor.

  2. Question 2Intermediate

    Classes & Namespaces · Virtual destructors and polymorphic deletion

    Case Study: A Game Development Studio

    A game development studio is creating a new 3D rendering engine. The engine needs to manage various types of game objects, such as Player, Enemy, and Scenery. Each object has a position in 3D space, but also contains type-specific data and behavior. For performance reasons, all game objects are stored in a single std::vector and are updated and rendered in a tight loop.

    Current Situation

    The initial design has a GameObject base class with virtual functions for update() and render(). When a GameObject is destroyed (e.g., an enemy is defeated), its memory must be reclaimed. The team has observed occasional crashes and memory corruption issues during long gameplay sessions, particularly when large numbers of objects are created and destroyed rapidly.

    Requirements

    1. The system must correctly manage the lifecycle of all derived GameObject types.
    2. When an object is deleted through a GameObject* pointer, the complete object, including derived parts, must be destroyed.
    3. The design should be extensible to allow for new GameObject types in the future without modifying the main game loop.
    4. The cause of the memory corruption must be eliminated.

    Proposed Code Snippet

    class GameObject {
    public:
    // Constructor and other members...
    virtual void update() = 0;
    virtual void render() = 0;
    // Missing destructor
    };
    
    class Enemy : public GameObject { ... };
    
    // In game loop:
    delete allGameObjects[i]; // i is the index of the object to be removed
    

    Which change is most critical to fix the memory corruption and meet the design requirements?

    Show answer & explanation

    Correct answer: C

    The most critical issue is the lack of a virtual destructor in the polymorphic base class GameObject. When delete is called on a base class pointer (GameObject*), if the destructor is not virtual, only the base class destructor is invoked. This leads to undefined behavior because the derived class's destructor (e.g., ~Enemy()) is never called, and resources owned by the derived class are not released. This is a classic cause of memory corruption and leaks in C++. Declaring the base class destructor as virtual ensures that the entire object hierarchy is destroyed correctly.

  3. Question 3Beginner

    Types & Operators · Bitwise AND operator

    What is the decimal value of the variable result after the following code executes?

    int flags = 0b10110; // 22 in decimal
    int mask = 0x1A; // 26 in decimal, 0b11010 in binary
    int result = flags & mask;
    
    Show answer & explanation

    Correct answer: C

    The bitwise AND operation (&) compares the bits of two numbers. A bit in the result is set to 1 only if the corresponding bits in both operands are 1.
    flags (0b10110)
    mask (0b11010)

    result(0b10010)

    The binary value 0b10010 is calculated as (1 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1), which equals 16 + 2 = 18.

  4. Question 4Intermediate

    Pointers · Passing arrays to functions

    A programmer needs to write a function that accepts an array of integers and its size, and it must modify the original array elements by doubling their value. Which function signature is the most appropriate and conventional C++ approach for this task?

    Show answer & explanation

    Correct answer: C

    In C++, when an array is passed to a function, it decays into a pointer to its first element. To modify the original array's contents, the function must accept a pointer to the element type. int* arr is the idiomatic way to declare a parameter that accepts an array of integers. The function can then use pointer arithmetic or array subscripting to access and modify the elements. A void return type is appropriate as the modifications are done in-place.

  5. Question 5Intermediate

    Types & Operators · Ternary operator and side effects

    What is the final value of x after the following code snippet is executed?

    int x = 10;
    int y = 5;
    
    x = (y > 3) ? ( (y 0) ? ++y : --y );
    
    Show answer & explanation

    Correct answer: B

    The expression is evaluated as follows:

    1. The outer condition (y > 3) is checked. Since y is 5, this is true.
    2. The true-branch of the outer ternary is evaluated: ( (y < 10) ? y++ : y-- ).
    3. The inner condition (y < 10) is checked. Since y is 5, this is true.
    4. The true-branch of the inner ternary is evaluated: y++.
    5. The post-increment operator y++ returns the current value of y (which is 5) and then increments y to 6.
    6. The value 5 is assigned to x.
  6. Question 6Beginner

    Functions & Preprocessor Directives · Recursion

    A developer needs to create a function that calculates the factorial of a number. They have decided to use recursion. Which of the following implementations is correct and handles a base case appropriately?

    Show answer & explanation

    Correct answer: B

    A recursive function must have a base case to terminate the recursion. For a factorial calculation, the base case is that the factorial of 0 or 1 is 1. This implementation correctly checks for n 1, it correctly performs the recursive step n * factorial(n - 1).

  7. Question 7Intermediate

    Classes & Namespaces · Friend functions

    A class DataProcessor is designed to handle sensitive information. To log internal state for debugging purposes, a free function logInternalState needs access to the private members of DataProcessor. Which mechanism should be used to grant this access without exposing the members publicly?

    Show answer & explanation

    Correct answer: D

    The friend keyword is the C++ mechanism for granting a non-member function or another class access to the private and protected members of a class. By adding the declaration friend void logInternalState(const DataProcessor&); inside the DataProcessor class, the logInternalState function is allowed to access DataProcessor's private members while still maintaining encapsulation for all other non-friend functions.

  8. Question 8Beginner

    Control & Exceptions · Switch statement fall-through

    What is the output of the following C++ code that demonstrates the behavior of a switch statement?

    #include
    
    int main() {
    int value = 2;
    switch (value) {
    case 1:
    std::cout << "A";
    case 2:
    std::cout << "B";
    case 3:
    std::cout << "C";
    break;
    default:
    std::cout << "D";
    }
    return 0;
    }
    
    Show answer & explanation

    Correct answer: B

    Execution begins at the matching case 2:. Since there is no break statement in case 2:, execution "falls through" to the next case, case 3:. The code in case 3: is executed, and then the break; statement is encountered, which terminates the switch block. Therefore, the output is "BC".

  9. Question 9Beginner

    Classes & Namespaces · Namespace aliases

    A developer wants to use a single namespace for a collection of utility functions but also wants to provide a shorter, more convenient alias for it within a specific implementation file. Which of the following code snippets correctly defines a namespace StringUtils and creates an alias SU for it?

    Show answer & explanation

    Correct answer: A

    The correct syntax for creating a namespace alias in C++ is namespace alias_name = original_namespace_name;. This creates a synonym for the namespace, which can be useful for shortening long namespace names or for versioning.

  10. Question 10Intermediate

    Pointers · Dynamic memory allocation for arrays

    What is the primary difference between delete ptr and delete[] ptr when managing dynamically allocated memory?

    Show answer & explanation

    Correct answer: B

    It is critical to match the deallocation form with the allocation form. new T allocates a single object and must be freed with delete. new T[N] allocates an array of N objects and must be freed with delete[]. Using the wrong form (e.g., delete on an array) results in undefined behavior. For non-trivial types (classes with destructors), this typically leads to only the first object's destructor being called, causing resource leaks.

Ready for the real thing?

The full CPA-21-02 simulator has every exam-style question, timed mode, and instant scoring.