typedef с CRTP не работает при использовании наследования - PullRequest
1 голос
/ 02 февраля 2012

Существуют ли способы определения типа с одинаковым именем для классов в отношениях наследования с использованием CTRP? Я попробовал следующий код, но получил error: member 'ptr_t' found in multiple base classes of different types от clang++.

#include <iostream>
#include <tr1/memory>

template <typename T> class Pointable {
public:
    // define a type `ptr_t` in the class `T` publicly
    typedef std::tr1::shared_ptr<T> ptr_t;
};

class Parent : public Pointable<Parent> {
public:
    Parent() {
        std::cout << "Parent created" << std::endl;
    }

    ~Parent() {
        std::cout << "Parent deleted" << std::endl;
    }
};

class Child : public Parent,
              public Pointable<Child> {
public:
    Child() {
        std::cout << "Child created" << std::endl;
    }

    ~Child() {
        std::cout << "Child deleted" << std::endl;
    }
};

int main(int argc, char** argv)
{
    Child::ptr_t child_ptr(new Child());
    Parent::ptr_t parent_ptr(new Parent());

    return 0;
}

Конечно, следующий вариант в порядке (но он избыточен и противоречит принципу СУХОЙ).

class Parent {
public:
    typedef std::tr1::shared_ptr<Parent> ptr_t;

    Parent() {
        std::cout << "Parent created" << std::endl;
    }

    ~Parent() {
        std::cout << "Parent deleted" << std::endl;
    }
};

class Child : public Parent {
public:
    typedef std::tr1::shared_ptr<Child> ptr_t;

    Child() {
        std::cout << "Child created" << std::endl;
    }

    ~Child() {
        std::cout << "Child deleted" << std::endl;
    }
};

Если нет способов добиться такого поведения с помощью CRTP, почему это запрещено?

Ответы [ 3 ]

2 голосов
/ 02 февраля 2012

Ваша проблема не имеет ничего общего с CRTP, но с множественным наследованием.Child наследует ptr_t от обоих базовых классов, и оба типа различаются: shared_ptr<Parent> против shared_ptr<Child>.Поэтому компилятор не может определить, какой тип вы подразумеваете под Child::ptr_t в main.

. Как вы указали, вы должны исправить это вручную, используя typedef в Child (делая ваш Pointable базовый класс бесполезен, хотя).

class Child : public Parent,
              public Pointable<Child> {
public:
    typedef Pointable<Child>::ptr_t ptr_t;
0 голосов
/ 02 февраля 2012

Если Child получен только из Parent (а не явно из Pointable), то это Pointable, если быть точным Pointabe<Parent>, потому что это Parent, а Parent is Pointable.

A Parent:: ptr_t может содержать экземпляр Child, потому что Child isa Parent (по крайней мере, в смысле кода).

Я не знаю, что вы хотите сделать с ptr_t.Вы теряете точный тип, но вы можете попытаться сделать dynamic_cast по иерархии.Возможно, этого достаточно.

0 голосов
/ 02 февраля 2012

Если предположить, что Child публично получен из Parent, нет способа, чтобы один и тот же typedef определялся по-разному в каждом из них, не помещая что-либо в определение Child. Как бы вы ни определяли наследование, Child будет наследовать неверный typedef от Parent.

Одна возможность - определить класс черт

  template<typename T> class Traits
  {
  public:
      typedef std::shared_ptr<T> ptr_t;
  }

Очевидно, что в этом случае это мало что дает, так как ссылка на Traits :: ptr_t длиннее, чем Child :: ptr_t. (Но это может быть полезно, если у вас много typedef или если вы хотите изменить тип указателя позже.)

...