API Design for C++


  • Martin Reddy, CEO, Code Reddy

API Design for C++ provides a comprehensive discussion of Application Programming Interface (API) development, from initial design through implementation, testing, documentation, release, versioning, maintenance, and deprecation. The book focuses on the issues of designing APIs for a single language (C++), which remains one of the most widely used programming languages for large software projects. The book also covers specialized API topics, such as creating scripting and plug-in APIs, with emphasis on API design. A discussion on testing strategies concentrates on automated API testing techniques rather than attempting to include end-user application testing techniques such as GUI testing, system testing, or manual testing. The book will be helpful to new programmers who understand the fundamentals of C++ and who want to advance their design skills, as well as senior engineers and software architects seeking to gain new expertise to complement their existing talents. Three specific groups of readers are targeted: practicing software engineers and architects, technical managers, and students and educators.
View full description


All software engineers developing C++ code to be used by other developers, whether via APIs, libraries, device drivers, or other reusable components.


Book information

  • Published: February 2011
  • ISBN: 978-0-12-385003-4


Martin Reddy draws from his experience on large scale, collaborative software projects to present patterns and practices that provide real value to individual developers as well as organizations. API Design for C++ explores often overlooked issues, both technical and non- technical, contributing to successful design decisions that produce high quality, robust, and long-lived APIs. - Eric Gregory, Software Architect, Pixar Animation Studios

"Intended for programmers with intermediate to advanced skills in the C++ programming language, this guide to the building of useful and robust application programming interfaces (APIs) provides practical instruction for software engineers developing systems on which downstream software engineers depend. The work provides a methodical approach to API design covering solution based API design, performance, versioning, documentation, testing, scripting, extensibility and libraries. The work includes numerous illustrations and code examples and access to additional online resources is provided. Reddy is a software development consultant."--Book News, Reference & Research

Table of Contents




Author Biography

Chapter 1 Introduction

1.1 What Are Application Programming Interfaces?

1.1.1 Contracts and Contractors

1.1.2 APIs in C++

1.2 What’s Different About API Design?

1.3 Why Should You Use APIs?

1.3.1 More Robust Code

1.3.2 Code Reuse

1.3.3 Parallel Development

1.4 When Should You Avoid APIs?

1.5 API Examples

1.5.1 Layers of APIs

1.5.2 A Real-Life Example

1.6 File Formats and Network Protocols

1.7 About This Book

Chapter 2 Qualities

2.1 Model the Problem Domain

2.1.1 Provide a Good Abstraction

2.1.2 Model the Key Objects

2.2 Hide Implementation Details

2.2.1 Physical Hiding: Declaration versus Definition

2.2.2 Logical Hiding: Encapsulation

2.2.3 Hide Member Variables

2.2.4 Hide Implementation Methods

2.2.5 Hide Implementation Classes

2.3 Minimally Complete

2.3.1 Don’t Overpromise

2.3.2 Add Virtual Functions Judiciously

2.3.3 Convenience APIs

2.4 Easy to Use

2.4.1 Discoverable

2.4.2 Difficult to Misuse

2.4.3 Consistent

2.4.4 Orthogonal

2.4.5 Robust Resource Allocation

2.4.6 Platform Independent

2.5 Loosely Coupled

2.5.1 Coupling by Name Only

2.5.2 Reducing Class Coupling

2.5.3 Intentional Redundancy

2.5.4 Manager Classes

2.5.5 Callbacks, Observers, and Notifications

2.6 Stable, Documented, and Tested

Chapter 3 Patterns

3.1 Pimpl Idiom

3.1.1 Using Pimpl

3.1.2 Copy Semantics

3.1.3 Pimpl and Smart Pointers

3.1.4 Advantages of Pimpl

3.1.5 Disadvantages of Pimpl

3.1.6 Opaque Pointers in C

3.2 Singleton

3.2.1 Implementing Singletons in C++

3.2.2 Making Singletons Thread Safe

3.2.3 Singleton versus Dependency Injection

3.2.4 Singleton versus Monostate

3.2.5 Singleton versus Session State

3.3 Factory Methods

3.3.1 Abstract Base Classes

3.3.2 Simple Factory Example

3.3.3 Extensible Factory Example

3.4 API Wrapping Patterns

3.4.1 The Proxy Pattern

3.4.2 The Adapter Pattern

3.4.3 The Facade Pattern

3.5 Observer Pattern

3.5.1 Model-View-Controller

3.5.2 Implementing the Observer Pattern

3.5.3 Push versus Pull Observers

Chapter 4 Design

4.1 A Case for Good Design

4.1.1 Accruing Technical Debt

4.1.2 Paying Back the Debt

4.1.3 Design for the Long Term

4.2 Gathering Functional Requirements

4.2.1 What Are Functional Requirements?

4.2.2 Example Functional Requirements

4.2.3 Maintaining the Requirements

4.3 Creating Use Cases

4.3.1 Developing Use Cases

4.3.2 Use Case Templates

4.3.3 Writing Good Use Cases

4.3.4 Requirements and Agile Development

4.4 Elements of API Design

4.5 Architecture Design

4.5.1 Developing an Architecture

4.5.2 Architecture Constraints

4.5.3 Identifying Major Abstractions

4.5.4 Inventing Key Objects

4.5.5 Architectural Patterns

4.5.6 Communicating the Architecture

4.6 Class Design

4.6.1 Object-Oriented Concepts

4.6.2 Class Design Options

4.6.3 Using Inheritance

4.6.4 Liskov Substitution Principle

4.6.5 The Open/Closed Principle

4.6.6 The Law of Demeter

4.6.7 Class Naming

4.7 Function Design

4.7.1 Function Design Options

4.7.2 Function Naming

4.7.3 Function Parameters

4.7.4 Error Handling

Chapter 5 Styles

5.1 Flat C APIs

5.1.1 ANSI C Features

5.1.2 Benefits of an ANSI C API

5.1.3 Writing an API in ANSI C

5.1.4 Calling C Functions from C++

5.1.5 Case Study: FMOD C API

5.2 Object-Oriented C++ APIs

5.2.1 Advantages of Object-Oriented APIs

5.2.2 Disadvantages of Object-Oriented APIs

5.2.3 Case Study: FMOD C++ API

5.3 Template-Based APIs

5.3.1 An Example Template-Based API

5.3.2 Templates versus Macros

5.3.3 Advantages of Template-Based APIs

5.3.4 Disadvantages of Template-Based APIs

5.4 Data-Driven APIs

5.4.1 Data-Driven Web Services

5.4.2 Advantages of Data-Driven APIs

5.4.3 Disadvantages of Data-Driven APIs

5.4.4 Supporting Variant Argument Lists

5.4.5 Case Study: FMOD Data-Driven API

Chapter 6 C++ Usage

6.1 Namespaces

6.2 Constructors and Assignment

6.2.1 Controlling Compiler-Generated Functions

6.2.2 Defining Constructors and Assignment

6.2.3 The Explicit Keyword

6.3 Const Correctness

6.3.1 Method Const Correctness

6.3.2 Parameter Const Correctness

6.3.3 Return Value Const Correctness

6.4 Templates

6.4.1 Template Terminology

6.4.2 Implicit Instantiation API Design

6.4.3 Explicit Instantiation API Design

6.5 Operator Overloading

6.5.1 Overloadable Operators

6.5.2 Free Operators versus Member Operators

6.5.3 Adding Operators to a Class

6.5.4 Operator Syntax

6.5.5 Conversion Operators

6.6 Function Parameters

6.6.1 Pointer versus Reference Parameters

6.6.2 Default Arguments

6.7 Avoid #define for Constants

6.8 Avoid Using Friends

6.9 Exporting Symbols

6.10 Coding Conventions

Chapter 7 Performance

7.1 Pass Input Arguments by Const Reference

7.2 Minimize #include Dependencies

7.2.1 Avoid “Winnebago” Headers

7.2.2 Forward Declarations

7.2.3 Redundant #include Guards

7.3 Declaring Constants

7.3.1 The New constexpr Keyword

7.4 Initialization Lists

7.5 Memory Optimization

7.6 Don’t Inline Until You Need To

7.7 Copy on Write

7.8 Iterating Over Elements

7.8.1 Iterators

7.8.2 Random Access

7.8.3 Array References

7.9 Performance Analysis

7.9.1 Time-Based Analysis

7.9.2 Memory-Based Analysis

7.9.3 Multithreading Analysis

Chapter 8 Versioning

8.1 Version Numbers

8.1.1 Version Number Significance

8.1.2 Esoteric Numbering Schemes

8.1.3 Creating a Version API

8.2 Software Branching Strategies

8.2.1 Branching Strategies

8.2.2 Branching Policies

8.2.3 APIs and Parallel Branches

8.2.4 File Formats and Parallel Products

8.3 Life Cycle of an API

8.4 Levels of Compatibility

8.4.1 Backward Compatibility

8.4.2 Functional Compatibility

8.4.3 Source Compatibility

8.4.4 Binary Compatibility

8.4.5 Forward Compatibility

8.5 How to Maintain Backward Compatibility

8.5.1 Adding Functionality

8.5.2 Changing Functionality

8.5.3 Deprecating Functionality

8.5.4 Removing Functionality

8.6 API Reviews

8.6.1 The Purpose of API Reviews

8.6.2 Prerelease API Reviews

8.6.3 Precommit API Reviews

Chapter 9 Documentation

9.1 Reasons to Write Documentation

9.1.1 Defining Behavior

9.1.2 Documenting the Interface’s Contract

9.1.3 Communicating Behavioral Changes

9.1.4 What to Document

9.2 Types of Documentation

9.2.1 Automated API Documentation

9.2.2 Overview Documentation

9.2.3 Examples and Tutorials

9.2.4 Release Notes

9.2.5 License Information

9.3 Documentation Usability

9.4 Using Doxygen

9.4.1 The Configuration File

9.4.2 Comment Style and Commands

9.4.3 API Comments

9.4.4 File Comments

9.4.5 Class Comments

9.4.6 Method Comments

9.4.7 Enum Comments

9.4.8 Sample Header with Documentation

Chapter 10 Testing

10.1 Reasons to Write Tests

10.2 Types of API Testing

10.2.1 Unit Testing

10.2.2 Integration Testing

10.2.3 Performance Testing

10.3 Writing Good Tests

10.3.1 Qualities of a Good Test

10.3.2 What to Test

10.3.3 Focusing the Testing Effort

10.3.4 Working with QA

10.4 Writing Testable Code

10.4.1 Test-Driven Development

10.4.2 Stub and Mock Objects

10.4.3 Testing Private Code

10.4.4 Using Assertions

10.4.5 Contract Programming

10.4.6 Record and Playback Functionality

10.4.7 Supporting Internationalization

10.5 Automated Testing Tools

10.5.1 Test Harnesses

10.5.2 Code Coverage

10.5.3 Bug Tracking

10.5.4 Continuous Build System

Chapter 11 Scripting

11.1 Adding Script Bindings

11.1.1 Extending versus Embedding

11.1.2 Advantages of Scripting

11.1.3 Language Compatibility Issues

11.1.4 Crossing the Language Barrier

11.2 Script-Binding Technologies

11.2.1 Boost Python

11.2.2 SWIG

11.2.3. Python-SIP

11.2.4 COM Automation

11.2.5 CORBA

11.3 Adding Python Bindings with Boost Python

11.3.1 Building Boost Python

11.3.2 Wrapping a C++ API with Boost Python

11.3.3 Constructors

11.3.4 Extending the Python API

11.3.5 Inheritance in C++

11.3.6 Cross-Language Polymorphism

11.3.7 Supporting Iterators

11.3.8 Putting It All Together

11.4 Adding Ruby Bindings with SWIG

11.4.1 Wrapping a C++ API with SWIG

11.4.2 Tuning the Ruby API

11.4.3 Constructors

11.4.4 Extending the Ruby API

11.4.5 Inheritance in C++

11.4.6 Cross-Language Polymorphism

11.4.7 Putting It All Together

Chapter 12 Extensibility

12.1 Extending via Plugins

12.1.1 Plugin Model Overview

12.1.2 Plugin System Design Issues

12.1.3 Implementing Plugins in C

12.1.4 The Plugin API

12.1.5 An Example Plugin

12.1.6 The Plugin Manager

12.1.7 Plugin Versioning

12.2 Extending via Inheritance

12.2.1 Adding Functionality

12.2.2 Modifying Functionality

12.2.3 Inheritance and the STL

12.2.4 Inheritance and Enums

12.2.5 The Visitor Pattern

12.2.6 Prohibiting Subclassing

12.3 Extending via Templates

12.3.1 Policy-Based Templates

12.3.2 The Curiously Recurring Template Pattern

Appendix A Libraries

A.1 Static versus Dynamic Libraries

A.1.1 Static Libraries

A.1.2 Dynamic Libraries

A.1.3 Dynamic Libraries as Plugins

A.2 Libraries on Windows

A.2.1 Importing and Exporting Functions

A.2.2 The DLL Entry Point

A.2.3 Creating Libraries on Windows

A.2.4 Useful Windows Utilities

A.2.5 Loading Plugins on Windows

A.3 Libraries on Linux

A.3.1 Creating Static Libraries on Linux

A.3.2 Creating Dynamic Libraries on Linux

A.3.3 Shared Library Entry Points

A.3.4 Useful Linux Utilities

A.3.5 Loading Plugins on Linux

A.3.6 Finding Dynamic Libraries at Run Time

A.4 Libraries on Mac OS X

A.4.1 Creating Static Libraries on Mac OS X

A.4.2 Creating Dynamic Libraries on Mac OS X

A.4.3 Frameworks on Mac OS X

A.4.4 Finding Dynamic Libraries at Run Time