Подтвердить что ты не робот

Как получить тип базового класса в С++?

Для этого конкретного проекта я не могу использовать возможности С++ 11 (например, decltype), потому что компилятор еще не поддерживает их. Мне нужно предоставить текущий класс в качестве параметра шаблона, предпочтительно внутри макроса без аргумента (см. Ниже), не наряжая декларацию class или скрывая фигурные скобки и т.д.

class Foo: private Bar<Foo> {
   MAGIC //expands to using Bar<Foo>::Baz; and some others
   public:
      void otherFunction();
      //... the rest of the class
};

В идеале я бы хотел, чтобы это работало так же, как макрос Qt Q_OBJECT, но без введения другого этапа предварительной компиляции и связанных с ним сгенерированных классов. typeid может быть полезен во время выполнения, но моя цель - выполнить все это при сборке.

Как написать макрос MAGIC, чтобы мне не нужно было каждый раз повторять имя класса?

4b9b3361

Ответ 1

Как насчет:

template<typename T>
class Base
{
protected:
    typedef Base<T> MagicBaseType;
    namespace Baz { }
};

class Derived1 : private Base<Derived1>
{
    using MagicBaseType::Baz;
}


class Derived1 : private Base<Derived2>
{
    using MagicBaseType::Baz;
}

или, если вы не можете изменить определение Base, используя шаблоны и множественное наследование

template<typename T>
class Base
{
protected:
    namespace Baz { }
};

template<typename T>
class DerivedTemplate : public T
{
protected:
    typedef typename T BaseType;
}

class Derived : public Base<Derived>, public DerivedTemplate<Base<Derived>>
{
using BaseType::Baz;
}

Ответ 2

Вы можете использовать структуру "proxy" (?) для построения наследования:

template <typename S>
struct Base : public S{ //always public, access is restricted by inheriting Base properly
    using super = S;
};

Использование будет следующим:

#include <iostream>

template <typename S>
struct Base : public S { 
    using super = S;
};

template <typename T>
class Bar
{
public:
    virtual void f() { std::cout << "Bar" << std::endl;  }
};

class Foo : private Base<Bar<int>>
{
public:
    virtual void f() 
    { 
        std::cout << "Foo";
        super::f();  //Calls Bar<int>::f()
    }
};

class Fii : private Base<Foo>
{
public:
    virtual void f() 
    {
        std::cout << "Fii";  
        super::f(); //Calls Foo::f()
    }
};


int main()
{
    Fii fii;
    fii.f(); //Print "FiiFooBar"
    return 0;
}

Ответ 3

Я не думаю, что существует какой-либо механизм, поддерживающий язык, для извлечения базового типа из класса. Вы можете использовать:

Вариант 1

class Foo: private Bar<Foo> {

#define BASE_TYPE Bar<Foo>
   // Use BASE_TYPE in MAGIC
   MAGIC //expands to using Bar<Foo>::Baz; and some others
#undef BASE_TYPE

   public:
      void otherFunction();
      //... the rest of the class
};

Вариант 2

class Foo: private Bar<Foo> {

    typedef Bar<Foo> BASE_TYPE;

   // Use BASE_TYPE in MAGIC
   MAGIC //expands to using Bar<Foo>::Baz; and some others

   public:
      void otherFunction();
      //... the rest of the class
};

Ответ 4

Если вы действительно не заботитесь о форматировании или написании головной боли обслуживания, вы можете сделать это, не повторяя тип, если макрос принимает аргумент типа:

#define MAGIC(BASE) \
BASE { \
    using BASE::baz;

class Sub : private MAGIC(Base<Foo>)

  public:
    void otherFunction();
};

но это заставляет меня чувствовать себя довольно плохо о себе