Const Usage and Member Functions
Proper Const Implementation
Modern compilers enforce const correctness by requiring const member functions to return const references:
class Document {
public:
const char& getCharAt(std::size_t index) const { return content[index]; }
private:
char* content;
};
When implementing both const and non-const versions of member functions, implement the const version first and have the non-const version call it:
// Const version
const char& getCharAt(std::size_t index) const { return content[index]; }
// Non-const version
char& getCharAt(std::size_t index) {
return const_cast<char>(
static_cast<const document="">(*this).getCharAt(index)
);
}
</const></char>
Object Initialization and Construction
Member Initialization Lists
Use member initialization lists rather than assignment in constructors. Built-in types default to zero values, and initialization follows declaration order.
Static Object Initialization
For non-local static objects, use local static objects within functions to guarantee proper initialization order:
class Database {
public:
static Database& instance() {
static Database db;
return db;
}
};
Compiler-Generated Functions and Prevention
Automatic Function Generation
Compilers automatically generate default constructor, copy constructor, and assignment operator if not explicitly defined.
Preventing Copy Operations
C++11 approach using delete keyword:
class NonCopyable {
public:
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
Resource Management and RAII
Smart Pointers
Use unique_ptr instead of deprecated auto_ptr. Use weak_ptr to break circular references in shared_ptr usage.
Resource Management Classes
Provide access to raw resources in resource management classes and define appropriate copying behavior.
Class Design and Interface Guidelines
Member Variable Access
Declare member variables as private to provide implementation flexibility and maintain encapsulation.
Parameter Passing
Prefer pass-by-reference-to-const over pass-by-value for custom types, while using pass-by-value for built-in types, iterators, and function objects.
Return Value Guidelines
Never return references to local variables or temporary objects. Modern compilers detect and warn about this issue.
Inheritance and Polymorphism
Virtual Function Alternatives
Non-virtual interface (NVI) pattern separates public interface from implementation:
class GameCharacter {
public:
int healthValue() const {
// Pre-processing
int result = calculateHealth();
// Post-processing
return result;
}
private:
virtual int calculateHealth() const { return 100; }
};
Strategy Pattern Implementation
Using function pointers or strategy objects instead of virtual functions:
class HealthCalculator {
public:
virtual int compute(const GameCharacter&) const = 0;
};
class DefaultHealthCalculator : public HealthCalculator {
public:
int compute(const GameCharacter&) const override { return 100; }
};
class GameCharacter {
public:
explicit GameCharacter(HealthCalculator* calculator = nullptr)
: healthCalculator(calculator ? calculator : &defaultCalculator) {}
int getHealth() const {
return healthCalculator->compute(*this);
}
private:
HealthCalculator* healthCalculator;
static DefaultHealthCalculator defaultCalculator;
};
Templates and Generic Programming
Template Base Class Name Resolution
When inheriting from template base classes, explicitly qualify base class member access:
template<typename company="">
class LoggingMessageSender : public MessageSender<company> {
public:
void sendWithLog(const MessageInfo& info) {
// Method 1: Use this->
this->transmit(info);
// Method 2: Using declaration
// using MessageSender<company>::transmit;
// transmit(info);
// Method 3: Explicit qualification
// MessageSender<company>::transmit(info);
}
};
</company></company></company></typename>
Member Function Templates
Use member function templates to accept all compatible types:
template<typename t="">
class SmartPointer {
public:
template<typename u="">
SmartPointer(const SmartPointer<u>& other)
: ptr(other.get()) {}
T* get() const { return ptr; }
private:
T* ptr;
};
</u></typename></typename>
Traits Classes
Use traits classes for compile-time type information and conditional logic:
template<typename iterator="">
struct iterator_traits {
typedef typename Iterator::value_type value_type;
};
// Specialization for pointer types
template<typename t="">
struct iterator_traits<t> {
typedef T value_type;
};
</t></typename></typename>
Advanced Techniques
Pimpl Idiom
Use pointer to implementation to reduce compilation dependencies and hide implementation details.
Copy and Swap
Implement exception-safe assignment using copy and swap technique:
class String {
public:
String& operator=(const String& other) {
String temp(other); // Copy
swap(temp); // Swap
return *this;
}
void swap(String& other) noexcept {
using std::swap;
swap(data, other.data);
swap(size, other.size);
}
private:
char* data;
std::size_t size;
};
Template Specialization
Use full and partial template specialization to provide specific implementations for particular types.