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

Для этого конкретного проекта я не могу использовать функции С++ 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
};

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

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


person multipleinterfaces    schedule 04.03.2016    source источник
comment
Этот вопрос кажется версией C++03 Могу ли я реализовать автономный тип члена self в C++?   -  person Lightness Races in Orbit    schedule 04.03.2016
comment
Не возражаете, если я изменю заголовок на base clase? окружающий класс звучит так, как будто вы вкладываете и какой тип вне внешнего класса.   -  person NathanOliver    schedule 04.03.2016
comment
Вопрос self выглядит очень похоже, но, как вы заметили, ни одно из предложенных решений не работает на С++ 03. Конечно, измените заголовок, если это сделает его более понятным.   -  person multipleinterfaces    schedule 04.03.2016
comment
В C++ нужно спросить какой базовый класс?   -  person Peter - Reinstate Monica    schedule 04.03.2016
comment
И мои 2 цента: это, вероятно, невозможно; вместо того, чтобы усиливать систему макросов, которая не была предназначена для нее, либо запустите свой код, например. через perl-скрипт; или найдите другое решение, использующее С++ (например, используйте уникальный int в качестве аргумента шаблона, а не имя типа).   -  person Peter - Reinstate Monica    schedule 04.03.2016
comment
stackoverflow.com/questions/8709340/   -  person Simon Kraemer    schedule 04.03.2016


Ответы (4)


Что о:

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

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

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;
}
person galinette    schedule 04.03.2016

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

Вариант 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
};
person R Sahu    schedule 04.03.2016
comment
Вы можете избежать избыточности, #define добавив BASE_TYPE перед объявлением класса, чтобы вы могли сказать class Foo : private BASE_TYPE. - person mindriot; 04.03.2016
comment
Или оставьте его в классе и используйте typedef вместо #define, как typdef Bar<Foo> BaseType; - person Simon Kraemer; 04.03.2016
comment
@RyanHaining, вот почему у меня #undef сразу после строки MAGIC. - person R Sahu; 05.03.2016

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

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

class Sub : private MAGIC(Base<Foo>)

  public:
    void otherFunction();
};

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

person Ryan Haining    schedule 04.03.2016

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

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;
}
person Simon Kraemer    schedule 04.03.2016