12 Advanced Puzzles, Tuples & Operators
Overview: Advanced Edge Cases & Type Grouping
This note covers advanced C++ edge cases, including Object Slicing, overriding private virtual methods,
std::tupleoperations, and logical keyword alternatives.
1. Object Slicing Mechanics
Object Slicing occurs when you assign a derived class object to a base class object by value.
Derived derivedObj;
Base baseObj = derivedObj; // Slicing occurs here!Under the Hood:
- Memory Allocation: The stack frame allocates only enough space for the size of
Base. - Member Discarding: During assignment, the copy constructor of
Baseruns. It copies the base portion ofderivedObjintobaseObjand discards (slices off) all member variables unique toDerived. - Vptr Reset: The
_vptrofbaseObjis set to point toBaseβsvtable, meaning it loses all polymorphic behavior.
How to prevent Slicing:
Always pass objects polymorphically by Reference (Base&) or Pointer (Base*). This maintains the original object memory layout and preserves the _vptr pointing to the derived classβs vtable.
2. Overriding Private Virtual Functions
An unusual but valid feature of C++: You can override private virtual functions of a base class.
class Base {
virtual void doWork(); // Private
};
class Derived : public Base {
void doWork() override; // Overrides Base::doWork
};Why does this compile?
- Access Control (
public/private) is verified by the compiler at compile time. - Virtual Method Lookup (Dynamic Dispatch) occurs at runtime using the
vtable. - The derived class cannot directly call the base private function, but it can override it to provide custom behavior when triggered from within the base class.
3. Strong Tuples (std::tuple)
std::tuple generalizes std::pair to hold an arbitrary number of values of different types.
auto t = std::make_tuple(10, 'A', 3.14);
int val = std::get<0>(t); // Retrieves first elementUnpacking via std::tie:
You can unpack tuples directly into individual variables:
int x; char y; double z;
std::tie(x, y, z) = t; // Unpacks elements into x, y, and zUse std::ignore as a placeholder if you want to skip unpacking specific elements.
4. Alternative Logical & Bitwise Keywords
C++ supports text-based alternative representations for operators (traditionally defined in <ciso646> but supported natively by modern compilers):
and&&or||not!xor^bitand&bitor|compl~
π» Conceptual Code Demonstration
#include <iostream>
#include <tuple>
class Parent {
public:
virtual void print() const { std::cout << "Parent class\n"; }
};
class Child : public Parent {
public:
void print() const override { std::cout << "Child class\n"; }
};
// Function demonstrating slicing vs reference parameter
void triggerSlicing(Parent p) { p.print(); } // Slices object!
void triggerRef(const Parent& p) { p.print(); } // Preserves polymorphism
int main() {
Child c;
std::cout << "--- 1. Object Slicing Demonstration ---\n";
triggerSlicing(c); // Prints: Parent class
triggerRef(c); // Prints: Child class
std::cout << "\n--- 2. Tuples Packing & Unpacking ---\n";
auto data = std::make_tuple(1, "Alice", 98.6);
int id;
std::string name;
double score;
// Unpack data tuple
std::tie(id, name, score) = data;
std::cout << "Unpacked: " << name << " (ID: " << id << ") -> " << score << '\n';
// 3. Alternative operator keywords
if (true and not false) { // Equivalent to: true && !false
std::cout << "Logical keywords compiled successfully!\n";
}
return 0;
}