Разные интерфейсы, одинаковые методы

hell0w0rd, возвращаемое значение нигде не учитывается :) Нельзя создавать 2 метода, которые отличаются только возвращаемым значением.
 
hell0w0rd, сигнатура метода не может включать возвращаемое значение. У Страуструпа есть примеры, когда это приводит к неразрешимым ситуациям.

Решить через базовый интерфейс можно было бы, если бы это были бы два полиморфных интерфейса, для которых предполагалось бы одинаковое поведение. В общем, если бы бабушка была дедушкой. Но ни анализ, ни проект, ни конструирование не дают предпосылок к полиморфизму. Это два разных интерфейса, как Iterator и Countable.

WMix, компилировал gcc 4.7.2 из пакетов Ubuntu.
Код:
#include<iostream>

namespace vendor1 {
  
struct IResolveCat {
    virtual void resolve() =0;
  
    virtual ~IResolveCat()
    {
    }
};

void explain(IResolveCat& resolver)
{
    resolver.resolve();
}

} // namespace vendor1

namespace vendorB {
  
struct IResolveDog {
    virtual void resolve() =0;
      
    virtual ~IResolveDog()
    {
    }
};

void explain(IResolveDog& resolver)
{
    resolver.resolve();
}

}// namespace vendorB

namespace my_namespace {
  
struct IResolveCat: public vendor1::IResolveCat {
    virtual void resolve()
    {
        resolveCat();
    }
  
    virtual ~IResolveCat()
    {
    }
  
    protected:
        virtual void resolveCat() =0;
};

struct IResolveDog: public vendorB::IResolveDog {
    virtual void resolve()
    {
        resolveDog();
    }
  
    virtual ~IResolveDog()
    {
    }
  
    protected:
        virtual void resolveDog() =0;
};
  
  
class Resolver: public virtual IResolveCat, public virtual IResolveDog {
    protected:
        virtual void resolveCat();
        virtual void resolveDog();
};

void Resolver::resolveCat()
{
    std::cout << "I'm a CAT resolved by Resolver" << std::endl;
}
      
void Resolver::resolveDog()
{
    std::cout << "I'm a DOG resolved by Resolver" << std::endl;
}

} //namespace my_namespace

int main(int args, char** argv)
{
    my_namespace::Resolver resolver;
  
    vendor1::explain(resolver);
    vendorB::explain(resolver);
  
    return 0;
}
 
WMix, компилировал gcc 4.7.2 из пакетов Ubuntu.
Код:
#include<iostream>

namespace vendor1 {

struct IResolveCat {
    virtual void resolve() =0;

    virtual ~IResolveCat()
    {
    }
};

.....
}

Ну вообще-то, в твоём примере, речь идёт больше о множественном наследии нежели об интерфейсах.
В php множественного наследия нет, но твой пример "легко" переводится на php:
PHP:
<?php

namespace {
    ini_set('display_errors', 1);
    error_reporting(E_ALL | E_STRICT);

    class Resolver
    {
        protected $list = [];

        public function __get($name)
        {
            if (isset($this->list[$name]))
            {
                return $this->list[$name];
            }
            throw new \Exception($name);
        }   
    }
}

namespace vendorA
{
    class IResolveCat
    {
        public function resolve()
        {
            $this->resolveCat();
        }

        protected function resolveCat()
        {
        }
    }

    /*
     * или вместо \Resolver какой-нибудь IResolver, 
     * чтобы не завязываться на конкретный класс
     */
    function explain(\Resolver $resolver)
    {
        //то, что ты в примере C++ прописал тип в параметре
        //и компилятор выдернул нужную структуру
        //здесь получаем её сами
        /** @var IResolveCat $cat */
        $cat = $resolver->{'IResolveCat'}; //или типа $resolve->getByName($name)
        $cat->resolve();
    }

} // namespace vendorA

namespace vendorB
{
    class IResolveDog
    {
        public function resolve()
        {
            $this->resolveDog();
        }

        protected function resolveDog()
        {
        }
    }

    function explain(\Resolver $resolver)
    {
        /** @var IResolveDog $dog */
        $dog = $resolver->{'IResolveDog'};
        $dog->resolve();
    }

} // namespace vendorB

namespace my_namespace
{
    class IResolveCat extends \vendorA\IResolveCat
    {
        protected function resolveCat()
        {
            echo 'Cat';
        }
    }

    class IResolveDog extends \vendorB\IResolveDog
    {
        protected function resolveDog()
        {
            echo 'Dog';
        }
    }

    class Resolver extends \Resolver
    {
        public function __construct()
        {
            $this->list['IResolveCat'] = new IResolveCat;
            $this->list['IResolveDog'] = new IResolveDog;
        }
    }
} //namespace my_namespace

namespace {
    $resolver = new \my_namespace\Resolver;
    \vendorA\explain($resolver);
    \vendorB\explain($resolver);
}
 
Последнее редактирование:
PHP:
<?php

class Dog{
    public function resolve( IResolveDog $resolver ){
        $resolver->resolveDog();
    }
}

class Cat{
    public function resolve( IResolveCat $resolver ){
        $resolver->resolveCat();
    }
}

interface IResolveDog{
    public function resolveDog();
}
interface IResolveCat{
    public function resolveCat();
}


class Resolver implements IResolveDog, IResolveCat{
    public function resolveCat(){
        echo "I'm a CAT resolved by Resolver";
    }
     
    public function resolveDog(){
        echo "I'm a DOG resolved by Resolver";
    }
}

$cat = new Cat;
$dog = new Dog;
$cat->resolve( new Resolver );
$dog->resolve( new Resolver );
 
  • Like
Реакции: riff
riff, в PHP примере есть существенное отличие от примера на C++: функции vendorA::explain и vendorB::explain принимают базовый \Resolver, который может быть им не известен.

множественное наследование
В С++ нет интерфейсов, но есть "чисто виртуальные методы", которые не предоставляют реализации. Фактически же структура с набором чисто виртуальных методов -- это в точности интерфейс.
Однако модель наследования в С++ хитрая, которая и достаточно гибкая и не слишком накладная. В частности, все "чисто виртуальные методы" всегда переопределяются. А вот виртуальные методы с базовой реализацией наследуются вместе с реализацией, то есть внутри производного класса создаются разные базовые сущности. На этом и основан пример. Это что-то хрестоматийное, бродит по всем книгам примеров (cook-book).

WMix, ваш пример не эквивалентен предложенному на C++. Он делает нечто похожее, но методы в интерфейсах IResolveDog и IResolveCat имеют разную сигнатуру. А проблема именно в том, что сигнатура одинаковая.
 
Последнее редактирование:
riff, в PHP примере есть существенное отличие от примера на C++: функции vendorA::explain и vendorB::explain принимают базовый \Resolver, который может быть им не известен.

Базовый класс, можно заменить на понятный им общий интерфейс, или вообще убрать тип, оставив просто "$resolve", всё таки мы не ограничены типитизацией параметров.
 
riff, это было бы возможно, если бы речь шла об одном-двух программистах. Если это разные группы, то так просто не пройдёт. А если это один-два программиста, то уж точно можно было бы просто поправить имена методов. Интерфейс -- это, всё же, контракт. Отказ от контракта -- это более сильное преступление, чем шов при конструировании.

Это, конечно, моё личное мнение. Но я лучше бы заставил программистов писать каждый раз явный вызов адаптера (вроде явного вызова привидения типов), чем позволил бы отказаться от контракта.
 
Последнее редактирование:
В С++ нет интерфейсов, но есть "чисто виртуальные методы", которые не предоставляют реализации. Фактически же структура с набором чисто виртуальных методов -- это в точности интерфейс....

Ну извини, уж как смог близко по смыслу перевёл твой пример. То, что "структура в C++ -- это в точности интерфейс" -- это ваш(сишников) плюс, а за рамки того что есть в php, перейти не могу, класс он и остаётся классом :)
 
WMix,
у тебя тоже самое
Нет, совершенно другое.

Сотри тип, это как "отстегни ремень безопасности".

Посмотрите ещё раз самый первый пост. Это условие. Его нарушать никак нельзя. Свои типы добавить можно, а вот изменить рисунок поставщиков никак.

Может это поможет Вам понять разницу.
 
Последнее редактирование:
riff, извиняю. Здесь дело каждого, как поступить. Если неожиданно совпадут методы из интерфейсов каких-нибудь корпоративных производителей, то с возможностями "убрать type-hint" или "переименовать метод" можно будет распрощаться. Да и вариант с композицией интерфейсов мне ближе. COM напоминает.
 
Lionishy, пока не понятно что ты хочешь!
то что у тебя выполняется в main, выполняется и у меня остальное это внутренняя реализация, и нет смысла ее повторять. добавь еще пару вызовов в main чтоб показать отличие твоего кода от моего!
 
WMix,
то что у тебя выполняется в main, выполняется и у меня остальное это внутренняя реализация
Нет. То, что у меня в main не выполняется в вашем коде. Explain требует два различных интерфейса, которые содержат одинаковый метод. У Вас методы разные.

К Вам с Марса и Венеры отправили два пакета кода:

PHP:
namespace Mars {
interface IResolver {
    /**
    */
    public functon resolve();
};

/**
* @param IResolver
*/
function doResolve(IResolver $resolver)
{
    $resolver->resolve()
}

} //namespace Mars

namespace Venus {
interface IResolver {
    /**
    */
    public functon resolve();
};

/**
* @param IResolver
*/
function doResolve(IResolver $resolver)
{
    $resolver->resolve()
}

} //namespace Venus

Есть необходимость одну и туже сущность передавать и в \Mars\doResolve, и в \Venus\doResolve.
Марсианский и Венерианский коды менять не получится, связь сегодня плохая, солнечная буря.

Как это сделать?
 
Lionishy, вот тебя кидает то...
еще раз для прапорщиков, покажи как ты собираешься использовать "два различных интерфейса, которые содержат одинаковый метод" просто напиши ЕЩЕ 2 вызова в main
в томже C++ коде
 
WMix, уже написаны две функции, которые используют одну и ту же сущность в двух различных аспектах, при этом внутри функций вызывается метод с одной и той же сигнатурой.
Как ещё вызовы Вы хотите, чтобы я написал?
 
еще раз, это внутренняя реализация, покажи отдельно и то и другое иначе все верят в то что реализация твоя довольно дибильная, нет смысла так закручивать.
интересно только то что реально используется, и откуда будет ответ! и это готово!
PHP:
$cat = new Cat;
$dog = new Dog;
$cat->resolve( new Resolver );
$dog->resolve( new Resolver );
 
WMix, я Вас совсем перестаю понимать.

Сформулируйте, что такое "внутренняя реализация" и почему она не является частью проекта.

На всякий случай.
Я бы назвал внутренней реализацией всё то, что не представлено в примере, а также реализацию функций vendor1::explain и vendor2::explain. А вот открытые интерфейсы, я бы никак не отнёс ко "внутреней реализации", кому бы эти открытые интерфейсы не принадлежали.
 
Последнее редактирование:
конструкция на команду $cat->resolve( new Resolver ); запускает resolveCat() в классе Resolver. это задача.
как она реализовано, остается за скобками. добавь вторую задачу но только снаружи в main что еще может твоя программа чего не может моя
 
WMix, откуда взялась задача про "вызвать resolveCat()"? Какую-нибудь мою цитату можете привести? Может быть я плохо изъясняюсь?

Задача состояла в том, чтобы на одной сущности можно было вызвать методы с идентичной сигнатурой, но из разных интерфейсов. Вы просили "компилируемый пример с функцией main", я привёл. Естественно, что в нём нет никакого содержания существенно. Это каркас. И он делает то, что написано курсивом.

Более широкий вариант: есть два пакета, которые требуют два разных контракта, каждый из которых определяет по методу с идентичными сигнатурами, нужно одну сущность (одну реализацию, одну алгебру) заставить работать синхронизировано в разных аспектах.

Первое -- очевидное решение второго.


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