Почему эта схема выдает ошибку «Несогласованная иерархия во время слияния C3»? - PullRequest
2 голосов
/ 27 апреля 2011
use parent qw<File::Spec::Unix File::Spec::Win32>;

И что - если что - я могу с этим поделать?

  • Хорошо, я понимаю, что Win32 наследуется от Unix, но отправка - Win32 -> Unix, и я хочу реализации Unix по умолчанию, пока я не переопределю ее и не отправлю вмоя реализация Win32.

  • Я также понимаю, что, поскольку File::Spec::x просто передает имена классов, наследование не является большой проблемой, но я должен задаться вопросом, что произойдет, если яна самом деле нужны некоторые классы для координации таким образом.

Ответы [ 2 ]

3 голосов
/ 27 апреля 2011

Концептуально это не имеет смысла. У вас нет чего-то, что является путем Unix и путем Windows.

Практически, это тоже не имеет смысла. В :: Win32 нет функции, которой нет в :: Unix.

File :: Spec уже злоупотребляет наследованием, и вы делаете шаг вперед. Наследование здесь не то, что вам нужно!

В любом случае, это будет эквивалентно тому, что у вас есть, за вычетом ошибки:

use parent qw( File::Spec::Unix );
use File::Spec::Win32 qw( ); 

sub isa {
    my ($self, $class) = @_;
    return $class eq 'File::Spec::Win32' || $self->SUPER::isa($class);
}
1 голос
/ 27 апреля 2011

Если вы хотите по умолчанию использовать File :: Spec :: Unix в общем и конкретно использовать File :: Spec :: Win32, вы не хотите использовать множественное наследование. File :: Spec :: Unix уже наследуется от File :: Spec :: Win32, поэтому вы установили (в основном) наследование алмазов, которое C3 не хочет разрешать.

   Unix
   /  \
Win32  |
   |   |
  YourCode

Вы просто хотите наследовать от File :: Spec :: Unix, а затем использовать File :: Spec :: Win32 по желанию.

package My::FileSpec;

use parent qw(File::Spec::Unix);
require File::Spec::Win32;

sub devnull {
    my $class = shift;
    return $class->File::Spec::Win32(@_);
}

Если вы хотите стать умным, вы можете исключить метод обертки.

*devnull = File::Spec::Win32->can("devnull");

Наконец, вы можете поместить это в цикл, чтобы избежать повторения.

my @Win32_Methods = qw(devnull tmpdir);
for my $method (@Win32_Methods) {
    my $code = File::Spec::Win32->can($method);
    die "File::Spec::Win32->$method does not exist" unless $code;

    no strict 'refs';
    *{$method} = $code;
}

Вы можете переопределить isa, чтобы утверждать, что вы File :: Spec :: Win32, а также File :: Spec :: Unix, но это не совсем так, и, вероятно, будет более запутанным, чем полезным только для вашего класса действует как Win32 для нескольких методов. Кроме того, File :: Spec не имеет объекта, поэтому он практически не появится.

Переопределение can необязательно, оно вернет правильные ссылки на код.

...