Fundamentals 13 min read

Mastering C++ Interfaces: Zero‑Overhead Techniques and Practical Patterns

This article explores various ways to implement interfaces in C++, comparing virtual functions, the Pimpl idiom, hidden subclasses, callback mechanisms, function pointers, std::function, member function pointers, and non‑intrusive traits, highlighting their trade‑offs in performance, binary compatibility, and design flexibility.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Mastering C++ Interfaces: Zero‑Overhead Techniques and Practical Patterns

Interface Classification

In C++ there is no built‑in interface concept, but several techniques can be used to achieve similar functionality. Interfaces can be divided into calling interfaces and callback interfaces.

Calling Interfaces

Example Network interface definition:

class Network {
public:
    bool send(const char* host, uint16_t port, const std::string& message);
};

Various implementations:

Virtual Functions

class Network {
public:
    virtual bool send(const char* host, uint16_t port, const std::string& message) = 0;
    static Network* New();
    static void Delete(Network* network);
};

Pros: simple. Cons: runtime overhead, binary incompatibility when adding functions.

Pointer to Implementation (Pimpl)

class NetworkImpl;
class Network {
public:
    bool send(const char* host, uint16_t port, const std::string& message);
    Network();
    ~Network();
private:
    NetworkImpl* impl;
};

The implementation is hidden behind a forward‑declared class, allowing users to manage object lifetime and preserving binary compatibility.

Hidden Subclass (Zero‑Overhead)

class Network {
public:
    bool send(const char* host, uint16_t port, const std::string& message);
    static Network* New();
    static void Delete(Network* network);
protected:
    Network();
    ~Network();
};

class NetworkImpl : public Network {
    friend class Network;
private:
    // members of Network
};

bool Network::send(const char* host, uint16_t port, const std::string& message) {
    NetworkImpl* impl = (NetworkImpl*)this;
    // use impl's members
}

This approach keeps the interface class free of data members, provides static creation/destruction, and incurs no virtual‑function overhead.

Callback Interfaces

Callback interfaces let the system invoke user‑provided code.

Using Virtual Functions

class Network {
public:
    class Listener {
    public:
        virtual void onReceive(const std::string& message) = 0;
    };
    bool send(const char* host, uint16_t port, const std::string& message);
    void registerListener(Listener* listener);
};

Function Pointer

class Network {
public:
    typedef void (*OnReceive)(const std::string& message, void* arg);
    bool send(const char* host, uint16_t port, const std::string& message);
    void registerListener(OnReceive listener, void* arg);
};

std::function

class Network {
public:
    using OnReceive = std::function<void(const std::string& message)>;
    bool send(const char* host, uint16_t port, const std::string& message);
    void registerListener(const OnReceive& listener);
};

Member Function Pointer

class Network {
public:
    class Listener { public: void onReceive(const std::string& message); };
    using OnReceive = void (Listener::*)(const std::string& message);
    bool send(const char* host, uint16_t port, const std::string& message);
    void registerListener(Listener* listener, OnReceive method);
    template<typename Class>
    void registerListener(Class* listener, void (Class::*method)(const std::string& message)) {
        registerListener((Listener*)listener, (OnReceive)method);
    }
};

Non‑intrusive Interfaces

Inspired by Rust traits, a non‑intrusive interface separates data from behavior. Example Serializable trait:

class Serializable {
public:
    virtual void serialize(std::string& buffer) const = 0;
};

The Network interface can depend on Serializable without requiring the user class to inherit from a base with virtual functions:

class Network {
public:
    bool send(const char* host, uint16_t port, const Serializable& s);
};

Concrete implementations such as IntSerializable can provide serialization for primitive types without modifying the original class.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CInterfacecallbackzero-overheadpimpl
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.