Main Content

Generate C++ Code with Class Interface

When you generate C code, the software analyzes your MATLAB® code and generates entry-point C functions corresponding to your entry-point MATLAB functions. When you generate C++ code, you can choose to generate entry-point functions as methods in a C++ class. Using this option:

  • You obtain more object-oriented code.

  • The code generator produces a class constructor and destructor that automatically perform memory initialization and termination.

  • You allocate memory for each class instance separately. The methods for each class instance are thread-safe and reentrant.

  • Multiple entry-point functions become methods in a single C++ class.

You can generate code with a class interface from the command line or from the MATLAB Coder™ app. From the command line, use the CppInterfaceStyle and CppInterfaceClassName configuration parameters. From the app, on the Generate Code step, select Language as C++, select Interface style as Methods, and then specify the C++ interface class name.

These examples show the command-line workflow.

Generate C++ Code with a Class Interface

This example shows how the generated C++ code differs when it uses a class interface.

MATLAB Algorithm

Consider a simple MATLAB function that performs operations on a matrix and outputs the result.

function out = foog %#codegen
I = eye(447);
out = ones(447)*I + 7;

Generate C++ Code With and Without Class Interface

To generate C++ code with a class interface, use the CppInterfaceStyle and CppInterfaceClassName parameters. Store the output in the withClass folder.

cfg = coder.config('lib');
cfg.GenCodeOnly = true;
cfg.TargetLang = 'C++';
cfg.CppInterfaceStyle = 'Methods';
cfg.CppInterfaceClassName = 'myClass';
codegen foog -config cfg -report -d withClass
Code generation successful: To view the report, open('withClass/html/report.mldatx')

Next, create a new configuration object and generate C++ code that does not use a class interface.

cfg = coder.config('lib');
cfg.GenCodeOnly = true;
cfg.TargetLang = "C++";
codegen foog -config cfg -report -d withoutClass
Code generation successful: To view the report, open('withoutClass/html/report.mldatx')

Inspect the generated example main function. Compare the versions with and without the class interface. With the class interface, the main function calls the entry-point function as a class method.

type withClass/examples/main.cpp

Class Definition and Implementation in the Generated Code

When the code generator produces code for the C++ interface class, it ensures that the function methods are reentrant. If the function methods use variables that can exceed the local stack memory limit, set by the configuration parameter StackUsageMax, then the code generator produces private data structures for the variables (identifiable by the suffix StackData), rather than declaring the variables as static. Static variables persist between function calls and are not reentrant. For information on generating reentrant C code, see Generating and Calling Reentrant Code.

To explore the generated class implementations, modify the function foog such that it contains a variable that exceeds the maximum stack usage specified by the configuration parameter StackUsageMax.

function out = foogBig %#codegen
I = eye(448);
out = ones(448)*I + 7;

The default value for StackUsageMax in bytes is:

cfg.StackUsageMax
ans =

  int32

   200000

Because fooBig uses a variable of 448^2 (200704) elements, and the code generator produces an 8-bit integer array to represent the variable, the default stack usage limit is exceeded by 704 bytes. Generate code for foogBig.

cfg = coder.config('lib','ecoder',false);
cfg.GenCodeOnly = true;
cfg.TargetLang = 'C++';
cfg.CppInterfaceStyle = 'Methods';
cfg.CppInterfaceClassName = 'myBigClass';
codegen foogBig -config cfg -report -d withBigClass
Code generation successful: To view the report, open('withBigClass/html/report.mldatx')

Inspect the Generated Interface Class Definitions

Inspect the class definitions for the foogBig project and for foog. The foogBig class stores variables that can exceed the maximum stack usage in a private class property, whereas the foog class only creates local variables on the stack.

When you work with a class definition that contains a StackData structure, indicating that the class requires data that exceeds the local stack usage limit, then allocate heap memory for the class instance by using new. See the generated example main file for your generated code for an example.

Globals and Persistents in a Generated C++ Class

When you generate C++ code with a class interface, then you access globals and persistents as members of the class. This example shows how to interact with globals and persistents in the class.

MATLAB Algorithm

Consider a MATLAB function that keeps count of the number of times you call it with a global and persistent variable.

function [po,go] = countCalls %#codegen
% increment persistent & global variable
persistent p
global g
if isempty(p)
    p = 0;
end
p = p+1;
g = g+1;
% set output variables 
po = double(p);
go = double(g);

Generate C++ Code with a Class Interface

For code generation, initialize the global variable in the workspace.

global g;
g = 0;

Generate code in the class called countClass.

cfg = coder.config('lib');
cfg.GenCodeOnly = true;
cfg.TargetLang = 'C++';
cfg.CppInterfaceStyle = 'Methods';
cfg.CppInterfaceClassName = "countClass";
codegen countCalls -config cfg -report
Code generation successful: To view the report, open('codegen/lib/countCalls/html/report.mldatx')

Inspect the Class Definition

In the generated C++ code, an initialization function sets the global variable to the value that you specify in the workspace. You can also specify the initial global value with the codegen -globals syntax.

Inspect the code for the class definition in the header file countClass.h.

type codegen/lib/countCalls/countClass.h

The global variable is a public member of the class. Access this variable from your main function as needed. The persistent variable is stored in a private class data structure.

Put Multiple Entry-Point Functions in the Same Class

When you generate C++ code for multiple entry-point functions and use the class interface setting, then each function becomes a public method of the same class. You can use this technique to create a simpler interface to your multiple entry-point function project.

MATLAB Entry-Point Functions

Break the function countCalls in the previous example into two, so that one function counts the calls with a persistent variable and the other counts the calls with a global variable. Inspect the two functions.

function po = countPersistent %#codegen
% increment persistent variable
persistent p
if isempty(p)
    p = 0;
end
p = p+1;
% set output variable
po = double(p);

function go = countGlobal %#codegen
% increment global variable
global g
g = g+1;
% set output variable
go = double(g);

Generate C++ Code

Use the codegen command and specify the initial global variable value as an input.

cfg = coder.config('lib');
cfg.GenCodeOnly = true;
cfg.TargetLang = 'C++';
cfg.CppInterfaceStyle = 'Methods';
cfg.CppInterfaceClassName = 'countClassMulti';
codegen countGlobal countPersistent -config cfg -report -globals {'g',0}
Code generation successful: To view the report, open('codegen/lib/countGlobal/html/report.mldatx')

Inspect the Generated Code

To see the generated class definition, open countClassMulti.h. Each entry-point function is a public method of the class.

type codegen/lib/countGlobal/countClassMulti.h

See Also

Related Topics