主要内容

本页采用了机器翻译。点击此处可查看英文原文。

部署从 MATLAB 句柄类继承的 MATLAB 类

R2026b
自 R2024a 起

数据 API:MATLAB® Data Array

此示例说明如何打包从 MATLAB 句柄类继承的 MATLAB 类并将其部署在 C++ 应用程序中。它使用 MATLAB Data API 来管理 MATLAB 函数和 C++ 应用程序之间的数据交换。该工作流支持Windows®、Linux® 和 macOS。

前提条件

  • 创建一个对 MATLAB 搜索路径可见的新工作文件夹。此示例使用名为 work 的文件夹。

  • 验证您是否已设置 C++ 开发环境。有关详细信息,请参阅设置 C++开发环境。本示例使用 MATLAB 作为 C++ 开发环境。因此,通过在 MATLAB 命令提示符下键入 mbuild -setup 来验证您是否已安装 C++ 编译器。

  • 验证您是否已满足所有 MATLAB Compiler SDK™ C++ 目标要求。有关详细信息,请参阅MATLAB Compiler SDK C++ 目标要求。

  • 最终用户必须安装 MATLAB Runtime 才能运行应用程序。有关详细信息,请参阅下载并安装 MATLAB Runtime。

    出于测试目的,您可以在运行 C++ 应用程序时使用 MATLAB 安装而不是 MATLAB Runtime。

句柄类支持

当您部署从 MATLAB 句柄类继承的 MATLAB 类时,现在支持以下功能:

  • 复制行为:MATLAB Compiler SDK 生成的 .hpp 文件允许创建模仿 MATLAB 句柄类的引用类型行为的 C++ 对象。当您在应用程序中创建这些 C++ 对象的副本时,原始对象和副本都引用相同的底层对象,类似于 MATLAB 处理对象行为。

  • 关系运算符:基于 .hpp 文件中的 MATLAB 句柄类定义创建的 C++ 对象支持关系运算。这允许在 C++ 中使用标准关系运算符(==、!=、<、>、<=、>=),类似于它们在 MATLAB 中的功能。

创建 MATLAB 函数

使用以下代码创建一个名为 BankAccount.m 的 MATLAB 文件:

classdef BankAccount < handle
    % BankAccount - A class for managing a bank account.
    %
    % This class provides methods to deposit, withdraw, and check the 
    % balance of a bank account.
    %
    % BankAccount Properties:
    %   Balance - The current balance of the account (private access).
    %
    % BankAccount Methods:
    %   BankAccount - Constructor, initializes account with a balance.
    %   deposit - Deposit money into the account.
    %   withdraw - Withdraw money from the account.
    %   checkBalance - Check the current balance of the account

    properties (Access = private)
        Balance (1,1) double {mustBeReal}
    end
    
    methods
        % Constructor to initialize the account with a balance
        function obj = BankAccount(initialBalance)
            arguments (Input)
                initialBalance (1,1) double {mustBeReal}
            end
            if nargin == 0
                initialBalance = 0;
            end
            obj.Balance = initialBalance;
        end
        
        % Method to deposit money
        function deposit(obj, amount)
            arguments (Input)
                obj (1,1) BankAccount
                amount (1,1) double {mustBeReal}
            end
            if amount > 0
                obj.Balance = obj.Balance + amount;
            else
                error('Amount must be positive');
            end
        end
        
        % Method to withdraw money
        function withdraw(obj, amount)
            arguments (Input)
                obj (1,1) BankAccount
                amount (1,1) double {mustBeReal}
            end
            if amount <= obj.Balance && amount > 0
                obj.Balance = obj.Balance - amount;
            else
                error('Insufficient funds or invalid amount');
            end
        end
        
        % Method to check the balance
        function bal = checkBalance(obj)
            arguments (Input)
                obj (1,1) BankAccount
            end
            arguments (Output)
                bal (1,1) double {mustBeReal}
            end
            bal = obj.Balance;
        end
    end
end

资深 MATLAB 用户可能会发现,在类中看到 properties 模块,在方法或函数中看到 arguments 模块,并且每个块都详细记录数据类型信息,这是很不寻常的。这两个模块都允许您用等效的 MATLAB 类型表示 C++ 数据类型。例如,如果您的 C++ 应用程序采用 double 数据类型来表示一个值,那么您现在可以在 MATLAB 中将其表示为 double。您还可以将 MATLAB 对象指定为参量或属性类型。例如,withdraw 方法将 BankAccount 指定为其中一个输入参量的类型。当 C++ 应用程序具有严格的类型要求时,这个指定类型的选项很有用。有关详细信息,请参阅C++ 和强类型 MATLAB 代码之间的数据类型映射。

在命令提示符下测试 MATLAB 类。

%% Create a new bank account with an initial balance of 100
account = BankAccount(100);

%% Deposit 50 into the account
account.deposit(50);
disp(['Balance after deposit: ', num2str(account.checkBalance())]);

%% Withdraw 30 from the account
account.withdraw(30);
disp(['Balance after withdrawal: ', num2str(account.checkBalance())]);

%% Create a joint account that references the same existing account
jointAccount = account;

%% Deposit 20 using the shared reference
jointAccount.deposit(20);
disp(['Balance from sharedAccount: ', num2str(jointAccount.checkBalance())]);
disp(['Balance from original account: ', num2str(account.checkBalance())]);
Balance after deposit: 150
Balance after withdrawal: 120
Balance from sharedAccount: 140
Balance from original account: 140

注意

MATLAB

使用 varargin 和 varargout 的函数不受支持。

使用 compiler.build.cppSharedLibrary 封装 MATLAB 函数

使用 compiler.build.cppSharedLibrary 函数从 MATLAB 函数创建代码存档(.ctf 文件)和头文件(.hpp 文件)。

buildResults = compiler.build.cppSharedLibrary("BankAccount.m",...
    OutputDir=".\output", Verbose="on");

该函数生成一套文件(如下所列),并将它们放在指定的 output 目录中。其中,集成过程中使用的关键文件是包含 MATLAB 代码的代码存档(.ctf 文件)和相应的头文件(.hpp 文件)。有关其他文件的信息,请参阅打包 MATLAB 函数后生成的文件。

P:\MATLAB\WORK\OUTPUT
│   GettingStarted.html
│   includedSupportPackages.txt
│   mccExcludedFiles.log
│   readme.txt
│   requiredMCRProducts.txt
│   unresolvedSymbols.txt
│
└───v2
    └───generic_interface
            BankAccount.ctf
            BankAccountv2.hpp
            readme.txt

为了完成集成,您需要来自 BankAccount.ctf 文件夹的 BankAccountv2.hpp 代码存档文件和 generic_interface 头文件。您可以在此处查看头文件:

#include "MatlabTypesInterface.hpp"
#include <map>

class BankAccount : public MATLABHandleObject<MATLABControllerType> {
public:

	friend bool operator==(const BankAccount& A, const BankAccount& B);
	friend bool operator!=(const BankAccount& A, const BankAccount& B);
	friend bool operator<(const BankAccount& A, const BankAccount& B);
	friend bool operator>(const BankAccount& A, const BankAccount& B);
	friend bool operator<=(const BankAccount& A, const BankAccount& B);
	friend bool operator>=(const BankAccount& A, const BankAccount& B);
	// constructors
	BankAccount() : MATLABHandleObject() {}

	BankAccount(std::shared_ptr<MATLABControllerType> _matlabPtr, double initialBalance) :
		MATLABHandleObject()
	{
		m_matlabPtr = _matlabPtr;
		matlab::data::ArrayFactory _arrayFactory;
		std::vector<matlab::data::Array> _args = {
			_arrayFactory.createArray<double>({1,1}, {initialBalance}) };
		matlab::data::Array _result = m_matlabPtr->feval(u"BankAccount", _args);
		m_object = _result;
	}


	BankAccount(std::shared_ptr<MATLABControllerType> matlabPtr, matlab::data::Array obj) :
		MATLABHandleObject(matlabPtr, obj)
	{}

	// properties

	// methods
private:
	template<size_t nargout>
	struct return_type_checkBalance { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_checkBalance<nargout>::type checkBalance() {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}
	void withdraw(double amount) {
		matlab::data::ArrayFactory _arrayFactory;
		std::vector<matlab::data::Array> _args = {
			m_object,
			_arrayFactory.createArray<double>({1,1}, {amount}) };
		m_matlabPtr->feval(u"withdraw", 0, _args);
	}
	void deposit(double amount) {
		matlab::data::ArrayFactory _arrayFactory;
		std::vector<matlab::data::Array> _args = {
			m_object,
			_arrayFactory.createArray<double>({1,1}, {amount}) };
		m_matlabPtr->feval(u"deposit", 0, _args);
	}

private:
	template<size_t nargout>
	struct return_type_eq { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_eq<nargout>::type eq(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

private:
	template<size_t nargout>
	struct return_type_ne { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_ne<nargout>::type ne(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

private:
	template<size_t nargout>
	struct return_type_lt { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_lt<nargout>::type lt(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

private:
	template<size_t nargout>
	struct return_type_gt { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_gt<nargout>::type gt(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

private:
	template<size_t nargout>
	struct return_type_le { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_le<nargout>::type le(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

private:
	template<size_t nargout>
	struct return_type_ge { typedef void type; };

public:
	template<size_t nargout = 1>
	typename return_type_ge<nargout>::type ge(matlab::data::Array B) {
		static_assert(nargout <= 1, "Too many outputs specified. Maximum outputs is 1.");
	}

};
template<>
struct BankAccount::return_type_checkBalance<0> { typedef void type; };

template<>
struct BankAccount::return_type_checkBalance<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::checkBalance<0>() {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object };
	m_matlabPtr->feval(u"checkBalance", 0, _args);
}
template<>
matlab::data::Array BankAccount::checkBalance<1>() {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"checkBalance", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_eq<0> { typedef void type; };

template<>
struct BankAccount::return_type_eq<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::eq<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"eq", 0, _args);
}
template<>
matlab::data::Array BankAccount::eq<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"eq", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_ne<0> { typedef void type; };

template<>
struct BankAccount::return_type_ne<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::ne<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"ne", 0, _args);
}

template<>
matlab::data::Array BankAccount::ne<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"ne", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_lt<0> { typedef void type; };

template<>
struct BankAccount::return_type_lt<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::lt<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"lt", 0, _args);
}

template<>
matlab::data::Array BankAccount::lt<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"lt", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_gt<0> { typedef void type; };

template<>
struct BankAccount::return_type_gt<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::gt<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"gt", 0, _args);
}
template<>
matlab::data::Array BankAccount::gt<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"gt", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_le<0> { typedef void type; };

template<>
struct BankAccount::return_type_le<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::le<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"le", 0, _args);
}
template<>
matlab::data::Array BankAccount::le<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"le", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}

template<>
struct BankAccount::return_type_ge<0> { typedef void type; };

template<>
struct BankAccount::return_type_ge<1> { typedef matlab::data::Array type; };

template<>
void BankAccount::ge<0>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	m_matlabPtr->feval(u"ge", 0, _args);
}
template<>
matlab::data::Array BankAccount::ge<1>(matlab::data::Array B) {
	matlab::data::ArrayFactory _arrayFactory;
	std::vector<matlab::data::Array> _args = {
		m_object,
		B };
	matlab::data::Array _result_mda = m_matlabPtr->feval(u"ge", _args);
	matlab::data::Array _result;
	_result = _result_mda;
	return _result;
}
bool operator==(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"eq", _args);
	bool _result = _result_mda[0];
	return _result;
}
bool operator!=(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"ne", _args);
	bool _result = _result_mda[0];
	return _result;
}
bool operator<(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"lt", _args);
	bool _result = _result_mda[0];
	return _result;
}
bool operator>(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"gt", _args);
	bool _result = _result_mda[0];
	return _result;
}
bool operator<=(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"le", _args);
	bool _result = _result_mda[0];
	return _result;
}
bool operator>=(const BankAccount& A, const BankAccount& B) {
	std::vector<matlab::data::Array> _args = { A.m_object, B.m_object };
	matlab::data::TypedArray<bool> _result_mda = A.m_matlabPtr->feval(u"ge", _args);
	bool _result = _result_mda[0];
	return _result;
}

MATLAB 类与 C++ 头文件之间的映射

MATLAB 类元素C++ 标头元素a

classdef BankAccount < handle 类定义,继承自 MATLAB 句柄类

class BankAccount : public MATLABHandleObject<MATLABControllerType>

MATLAB 句柄类的概念在 C++ 中通过使用 MATLABHandleObject 实现。

function obj = BankAccount(initialBalance) 构造函数

BankAccount(std::shared_ptr<MATLABControllerType> _matlabPtr, double initialBalance)

function deposit(obj, amount) 方法

void deposit(double amount)

function withdraw(obj, amount) 方法

void withdraw(double amount)

function bal = checkBalance(obj) 方法

matlab::data::Array checkBalance<1>()

从 MATLAB 句柄类继承的关系运算符

  • ==

  • !=

  • <

  • >

  • <=

  • >=

bool operator==

bool operator!=

bool operator<

bool operator>

bool operator<=

bool operator>=

a Input arguments are in C++ data types corresponding to those defined in the MATLAB class' arguments block.

注意

生成的工件不包括 MATLAB Runtime 或安装程序。要使用 buildResults 对象创建安装程序,请参阅 compiler.package.installer。

将 MATLAB 代码存档集成到 C++ 应用程序中

您可以在首选的 C++ 开发环境中完成集成过程,包括 MATLAB 或 Windows 上的 Microsoft® Visual Studio® 等替代方案。但是,此示例使用 MATLAB 作为 C++ 开发环境。有关详细信息,请参阅设置 C++开发环境。

要将生成的 MATLAB 代码存档(.ctf 文件)和头文件(.hpp 文件)集成到 C++ 应用程序中,请遵循以下准则:

  • 使用 #include 指令将生成的头文件(.hpp 文件)合并到您的 C++ 应用程序代码中。

  • 确保代码存档(.ctf 文件)位于 C++ 可执行文件可以访问的位置。

完成集成步骤需要熟练的 C++ 技能来编写应用程序代码。编写自己的应用程序时,可以使用以下示例 C++ 应用程序代码作为指南。

  1. 在此示例的 work 文件夹中,创建一个名为 BankAccountCppConsoleApp.cpp 的新文件,并包含以下代码。

    #include <iostream>
    #include "MatlabCppSharedLib.hpp"
    #include "P:\MATLAB\work\output\v2\generic_interface\BankAccountv2.hpp"
    
    
    void displayBalance(BankAccount& account) {
        try {
            auto balance = account.checkBalance<1>();
            double currentBalance = balance[0];
            std::cout << "Current balance: $" << currentBalance << std::endl;
        }
        catch (const std::exception& e) {
            std::cerr << "Error while checking balance: " << e.what() << std::endl;
        }
    }
    
    // Start MATLAB Runtime, initialize it, and return an object to it
    std::shared_ptr<matlab::cpplib::MATLABApplication> setup()
    {
        auto mode = matlab::cpplib::MATLABApplicationMode::IN_PROCESS;
        std::vector<std::u16string> options = { u"-nojvm" };
        std::shared_ptr<matlab::cpplib::MATLABApplication> matlabApplication =
            matlab::cpplib::initMATLABApplication(mode, options);
        return matlabApplication;
    }
    
    // Initialize the code archive (.ctf file), specify input arguments, call the MATLAB function, 
    // and print the result
    int mainFunc(std::shared_ptr<matlab::cpplib::MATLABApplication> app, const int argc, const char* argv[])
    {
        try {
            auto libPtr = matlab::cpplib::initMATLABLibrary(app, u"BankAccount.ctf");
            std::shared_ptr<MATLABControllerType> matlabPtr(std::move(libPtr));
    
            //Create a bank account object with an initial balance of 100
            BankAccount account(matlabPtr, 100.0);
            std::cout << "Created a bank account with an initial balance of $100" << std::endl;
    
            //Deposit 50 into the account
            account.deposit(50.0);
            std::cout << "Deposited $50" << std::endl;
            displayBalance(account);
    
            //Withdraw 30 from the account
            account.withdraw(30.0);
            std::cout << "Withdrew $30" << std::endl;
            displayBalance(account);
    
            // Created a joint account using that references the same existing account
            BankAccount jointAccount = account;
            std::cout << "Created a joint account" << std::endl;
    
            // Check if the accounts are the same (showcase == operator)
            bool sameAccount = account == jointAccount;
            std::cout << "Are the account and joint account the same? " << std::boolalpha << sameAccount << std::endl;
    
            // Deposit 20 into the joint account
            jointAccount.deposit(20.0);
    
            // Original account balance
            std::cout << "Original account:" << std::endl;
            displayBalance(account);
    
            // Joint account balance
            std::cout << "Joint account:" << std::endl;
            displayBalance(jointAccount);
    
        }
        catch (const std::exception& exc) {
            std::cerr << "Error: " << exc.what() << std::endl;
            return -1;
        }
        return 0;
    }
    
    // Call setup() to initialize MATLAB Runtime, use runMain() to run mainFunc(), 
    // and reset MATLAB Runtime after completion
    int main(const int argc, const char* argv[])
    {
        int ret = 0;
        try {
            auto matlabApplication = setup();
            ret = matlab::cpplib::runMain(mainFunc, std::move(matlabApplication), argc, argv);
            matlabApplication.reset();
        }
        catch (const std::exception& exc) {
            std::cerr << exc.what() << std::endl;
            return -1;
        }
        return ret;
    }
    
  2. 通过在 MATLAB 命令提示符下执行 mbuild 函数来编译和链接应用程序。

    mbuild -v BankAccountCppConsoleApp.cpp -outdir output\bin

处理代码存档(.ctf 文件)

为确保您的 C++ 应用程序可以访问包含 MATLAB 代码的代码存档(.ctf 文件),请将该文件放置在可执行文件可访问的位置。对于这个示例,我们将通过在 MATLAB 桌面环境中设置 CPPSHARED_BASE_CTF_PATH 环境变量来实现这一点。

setenv("CPPSHARED_BASE_CTF_PATH","P:\MATLAB\work\output\v2\generic_interface")

如果您使用的是 Visual Studio,请参阅在 Visual Studio 中设置环境变量。

有关代码存档(.ctf 文件)放置选项的完整列表,请参阅代码存档(.ctf 文件)的放置。

运行 C++ 应用程序

为了测试目的,您可以从 MATLAB 命令提示符运行该应用程序。这不需要安装 MATLAB Runtime。

!output\bin\BankAccountCppConsoleApp.exe
Created a bank account with an initial balance of $100
Deposited $50
Current balance: $150
Withdrew $30
Current balance: $120
Created a joint account
Are the account and joint account the same? true
Original account:
Current balance: $140
Joint account:
Current balance: $140

另请参阅

|

主题