Есть ли способ переслать объявление ковариации?

StackOverflow https://stackoverflow.com/questions/1259272

Вопрос

Предположим, у меня есть эти абстрактные классы Foo и Bar:

class Foo;
class Bar;

class Foo
{
public:
  virtual Bar* bar() = 0;
};

class Bar
{
public:
  virtual Foo* foo() = 0;
};

Предположим далее, что у меня есть производный класс ConcreteFoo и ConcreteBar.Я хочу ковариантно уточнить тип возвращаемого значения foo() и bar() такие методы:

class ConcreteFoo : public Foo
{
public:
  ConcreteBar* bar();
};

class ConcreteBar : public Bar
{
public:
  ConcreteFoo* foo();
};

Это не скомпилируется, поскольку наш любимый однопроходный компилятор не знает этого. ConcreteBar будет наследовать от Bar, и так что ConcreteBar является совершенно допустимым ковариантным возвращаемым типом.Простое заявление ConcreteBar также не работает, поскольку ничего не сообщает компилятору о наследовании.

Является ли это недостатком C++, с которым мне придется смириться, или на самом деле есть способ обойти эту дилемму?

Это было полезно?

Решение

Вы можете легко его подделать, но при этом потеряете статическую проверку типов.Если вы замените dynamic_casts к static_casts, у вас есть то, что компилятор использует внутри себя, но у вас нет ни динамической, ни статической проверки типа:

class Foo;
class Bar;

class Foo
{
public:
  Bar* bar();
protected:
  virtual Bar* doBar();
};

class Bar;
{
public:
  Foo* foo();
public:
  virtual Foo* doFoo();
};

inline Bar* Foo::bar() { return doBar(); }
inline Foo* Bar::foo() { return doFoo(); }

class ConcreteFoo;
class ConcreteBar;
class ConcreteFoo : public Foo
{
public:
  ConcreteBar* bar();
protected:
  Bar* doBar();
};

class ConcreteBar : public Bar
{
public:
   ConcreteFoo* foo();
public:
   Foo* doFoo();
};

inline ConcreteBar* ConcreteFoo::bar() { return &dynamic_cast<ConcreteBar&>(*doBar()); }
inline ConcreteFoo* ConcreteBar::foo() { return &dynamic_cast<ConcreteFoo&>(*doFoo()); }

Другие советы

Разве статический полиморфизм не решает вашу проблему?Передача базового класса производному классу через аргумент шаблона?Значит, базовый класс будет знать производный тип и объявить правильный виртуальный?

Ковариация основана на диаграмме наследования, поэтому, поскольку вы не можете объявить

class ConcreteBar : public Bar;

следовательно, нет способа сообщить компилятору о ковариации.

Но вы можете сделать это с помощью шаблонов, объявив ConcretFoo::bar как шаблон, а последующее ограничение позволит вам решить эту проблему.

Как насчет этого.

template <class BarType>
class Foo
{
public:
    virtual BarType* bar() = 0;
};

template <class FooType>
class Bar
{
public:
    virtual FooType* foo() = 0;
};

class ConcreteBar;
class ConcreteFoo : public Foo<ConcreteBar>
{
public:
    ConcreteBar* bar();
};

class ConcreteBar : public Bar<ConcreteFoo>
{
public:
    ConcreteFoo* foo();
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top