首页 > 解决方案 > #define 类外宏

问题描述

我不太明白这里宏的用法:

在 Dog.cpp 中,在类范围之外有这个:

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)

在 Animals.h 中有一个宏定义,也可以在 Animal 类范围之外找到:


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)     }

我不明白这实际上是如何工作的。为什么允许在类外重新定义方法SetupSetParamMap()?如果是这样,这会覆盖 Animal 类的实现吗?

我不知道上面的代码如何编译得很好。

我尝试创建一个更简单的示例,但出现语法错误:

// 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;
}

这是错误:

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

帮助,任何人?

标签: c++macros

解决方案


我不明白这实际上是如何工作的。为什么允许在类外重新定义方法 SetupSetParamMap()?

该代码之所以有效,是因为它没有定义方法 Animal::SetupSetParamMap。宏的作用是允许您为另一种对象类型实现 SomeDerivedAnimalType::SetupSetParamMap。如果您尝试执行:BEGIN_SETPARAM_MAP(Animal),那么现在您将遇到 Animal::SetupSetParamMap 的重新定义错误。但是 BEGIN_SETPARAM_MAP(Sheep) 不会引起问题。

对于第二个代码示例,编译器错误是非常不言自明的......(你清楚地已经识别出来了!)

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; \
} 

这是一个稍微简单的示例,让您了解一下;)

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;
}

推荐阅读