Reputation: 1768
I do not quite understand this usage of macros here:
In Dog.cpp, there is this outside the class scope:
BEGIN_SETPARAM_MAP(Dog)
MAP_SETPARAM(eParam_Macro_Eat, Eat)
MAP_SETPARAM(eParam_Macro_Walk, Walk)
MAP_SETPARAM(eParam_Macro_Sleep, Sleep)
END_GETPARAM_MAP(Dog)
And in Animals.h there is this a macro definition, also found outside the Animal class scope:
class Animal
{
protected:
HRESULT MapSetParamHandler(ULONG paramId, ParamValueHandler handler);
virtual void SetupSetParamMap(void) {}
};
#define BEGIN_SETPARAM_MAP(className) void className::SetupSetParamMap(void) {typedef className ThisClass;
#define MAP_SETPARAM(paramId, handler) MapSetParamHandler(paramId, static_cast<ParamValueHandler>(&ThisClass::handler));
#define END_SETPARAM_MAP(className) }
I don't understand how this actually works. Why is it allowed to re-define the method SetupSetParamMap()
outside the class? If so, will this override the implementation on the Animal class?
I have no idea how the code above compiles just fine.
I tried creating a simpler example but I am getting a syntax error:
// Example program
#include <iostream>
#include <string>
class Animal
{
public:
void cuddle()
{
std::cout << "Cuddle" << std::endl;
}
};
class Dog : public Animal
{
public:
void bark()
{
std::cout << "Bark" << std::endl;
cuddle();
}
virtual void sleep(){}
};
#define BEGIN_SETPARAM_MAP(className) void Dog::sleep() \
{ \
std::cout << "sleep" << std::endl; \
}
BEGIN_SETPARAM_MAP(Dog);
int main()
{
Dog dog;
dog.bark();
dog.sleep();
return 0;
}
Here is the error:
25:44: error: redefinition of 'void Dog::sleep()'
30:1: note: in expansion of macro 'BEGIN_SETPARAM_MAP'
22:18: note: 'virtual void Dog::sleep()' previously defined here
Help, anyone??
Upvotes: 1
Views: 541
Reputation: 9668
I don't understand how this actually works. Why is it allowed to re-define the method SetupSetParamMap() outside the class?
The code works simply because it is not defining the method Animal::SetupSetParamMap. What the macro does is allow you to implement SomeDerivedAnimalType::SetupSetParamMap for another object type. If you attempted to do: BEGIN_SETPARAM_MAP(Animal), then now you would have a redefinition error for Animal::SetupSetParamMap. However BEGIN_SETPARAM_MAP(Sheep) would not cause a problem.
wrt to the second code example, the compiler error is pretty self explanatory... (and you clearly have identified it!)
class Dog : public Animal
{
public:
void bark()
{
std::cout << "Bark" << std::endl;
cuddle();
}
virtual void sleep(){} ///< I AM THE IMPLEMENTATION OF Dog::sleep
};
/// I AM ALSO THE IMPLEMENTATION OF Dog::sleep, and therefore an error...
#define BEGIN_SETPARAM_MAP(className) void Dog::sleep() \
{ \
std::cout << "sleep" << std::endl; \
}
Here's a slightly simpler example for you to get your head around ;)
class Animal
{
public:
/// I need to be implemented for each animal
/// It's boiler-plate repetition, so lets macro this
virtual void speak() = 0;
};
// use within the class definition to add capabilities
#define CAN_SPEAK(animalType) void speak() override;
// use to implement the boiler plate code of the method
#define MAKE_SPEAK(animalType, noise) void animalType::speak() \
{ \
std::cout << noise << std::endl; \
}
// here's a dog that says woof
class Dog : public Animal
{
public:
CAN_SPEAK(Dog)
};
MAKE_SPEAK(Dog, "woof")
// ... and a sheep that says baa
class Sheep : public Animal
{
public:
CAN_SPEAK(Sheep)
};
MAKE_SPEAK(Sheep, "baa")
int main()
{
std::vector<Animal*> animals;
animals.push_back(new Dog);
animals.push_back(new Sheep);
for(auto animal : animals)
{
animal->speak();
}
/* yes, I should be freeing the memory here... */
return 0;
}
Upvotes: 1