This article demonstrates the use of CoreModifiable methods - how to declare them, how to define them and how to call them. CoreModifiable methods are an important mechanism used by signal / slot management and notification among others.

Table of Contents
Check Already Published in this Series section to know what was seen before.
In this article, we will focus on CoreModifiable
methods. CoreModifiable
methods are methods that can be called by their name without knowing the exact type of the called instance.
Fixed prototype is:
bool methodName(CoreModifiable* sender,
std::vector<CoreModifiableAttribute*>& params,void* privateParams);
Parameters are:
CoreModifiable* sender
: caller class std::vector<CoreModifiableAttribute*>& params
: vector
of CoreModifiableAttribute*
parameters void* privateParams
: a possible user-defined private param
The return value is a bool
value. The meaning of the return value is user-defined.
Helper macros can be used to declare a member method: DECLARE_METHOD
, DECLARE_VIRTUAL_METHOD
, DECLARE_PURE_VIRTUAL_METHOD
, DECLARE_OVERRIDE_METHOD
.
DECLARE_METHOD(GiveInfos);
Then COREMODIFIABLE_METHODS must be used to list all the methods declared with one of the previous helper macro ( or directly using the CoreModifiable method prototype ) :
COREMODIFIABLE_METHODS(GiveInfos);
Helper macro DEFINE_METHOD
is then used to define method:
DEFINE_METHOD(SimpleClass, GiveInfos)
{
std::cout << "SimpleClass GiveInfos method called on
" << getName() << " instance" << std::endl;
std::cout << "-- sender : " << sender->getName() << std::endl;
for (auto p : params)
{
std::string v;
if (p->getValue(v,this))
{
std::cout << "-- parameter : " << p->id() <<
" value is : " << v << std::endl;
}
else
{
std::cout << "-- parameter : " << p->id() <<
" value cannot be evaluated as string" << std::endl;
}
}
if(privateParams)
std::cout << "-- private parameter is not null" << std::endl;
else
std::cout << "-- private parameter is null" << std::endl;
return true;
}
Then method can be called with "CallMethod
" like this:
AddDynamicAttribute<maFloat, float>("FloatParam", 12.0f);
CoreModifiableAttribute* intParam = new maInt("IntParam", 15);
std::vector<CoreModifiableAttribute*> params;
params.push_back(getAttribute("FloatParam"));
params.push_back(intParam);
bool result = instance1->CallMethod("GiveInfos", params, nullptr, nullptr);
std::cout << "GiveInfos returns " << (result?"true":"false") << std::endl << std::endl;
The SimpleCall
template method automatically encodes parameters in vector:
result = instance2->SimpleCall("GiveInfos", 32,64,5);
std::cout << "GiveInfos returns " << (result ? "true" : "false") << std::endl << std::endl;
Returned value can be pushed on parameter vector with helper macro PUSH_RETURN_VALUE
.
When called using CallMethod
, the returned value and allocated parameters must be deleted after the call (or a memory leaks will occur).
int paramsCount = params.size();
result = instance2->CallMethod("GiveInfos", params, nullptr, nullptr);
if (params.size() > paramsCount)
{
while(paramsCount<params.size())
{
std::string v;
if(params.back()->getValue(v,this))
std::cout << "GiveInfos returned value = " << v << std::endl;
delete params.back();
params.pop_back();
}
}
std::cout << "GiveInfos returns " << (result ? "true" : "false") << std::endl << std::endl;
With SimpleCall
, the returned value can be managed automatically with template parameter:
float floatresult = instance2->SimpleCall<float>("GiveInfos", 32,64,5);
std::cout << "GiveInfos returns " << floatresult << std::endl << std::endl;
Any member method can be wrapped as a CoreModifiable
method. In class declaration:
float Multiply(float v1, float v2)
{
return v1 * v2;
}
WRAP_METHODS(Multiply);
Then Multiply
method can be called like this:
float floatresult = instance2->SimpleCall<float>("Multiply", 32, 5);
std::cout << "instance2 Multiply returns " << floatresult << std::endl << std::endl;
CoreModifiable
inherited instances can be enhanced with dynamic method.
A dynamic method can be defined like this:
DEFINE_DYNAMIC_METHOD(CoreModifiable, addValues)
{
float result = 0.0f;
for (auto p : params)
{
float v;
if (p->getValue(v,this))
{
result += v;
}
}
PUSH_RETURN_VALUE(result);
return true;
}
Then at run time, add this method to a given instance, and call it with SimpleCall
:
instance2->INSERT_DYNAMIC_METHOD(addValues, addValues);
floatresult = instance2->SimpleCall<float>("addValues", 32, 5);
std::cout << "instance2 addValues returns " << floatresult << std::endl << std::endl;
This mechanism can be used to decorate instances with a specific behaviour.
Find all the sample code from this article in Sample4 project (browse the code).
- Kigs Framework Introduction (1/8) - Overview
- Kigs Framework Introduction (2/8) - CoreModifiable
- Kigs Framework Introduction (3/8) - Attributes
- Kigs Framework Introduction (4/8) - Methods
- Kigs Framework Introduction (5/8) - CoreItem
- Kigs Framework Introduction (6/8) - Signal, Slot, Notification
- Kigs Framework Introduction (7/8) - Lua Binding
- Kigs Framework Introduction (8/8) - Data Driven Application
- 13th February, 2020: Initial version
- 21st February, 2020: Article (5/8) added to the series
- 3rd March, 2020: Article (6/8) added to the series
- 19th March, 2020: Article (7/8) added to the series
- 17th June, 2020 : Added final article of the series
- 1st March, 2023: Article updated after framework refactory