Идиома Pimpl по сравнению с Чистым виртуальным интерфейсом класса

Вы можете использовать /e, модифицированный для выполнения кода (для каждого совпадения отдельно) для генерации строки замены:

use strict;
use warnings;

my $start_regex  = qr/a.*?b/;
my $end_regex    = qr/c.*?d/;
my $string = 'a1b x c2d x a345b qqxxxc678d xx abxcd';

$string =~ s/($start_regex)(.*?)($end_regex)/ my ($start_match, $middle_match, $end_match) = ($1, $2, $3); $middle_match =~ s!x!y!g; $start_match . $middle_match . $end_match /eg;

print $string, "\n";

Распечатает

a1b y c2d x a345b qqyyyc678d xx abycd

Обратите внимание на альтернативу разделитель регулярных выражений s!!! во внутреннем регулярном выражении.

Важно хранить $1, $2 и $3 внешнего соответствия регулярному выражению во временных переменных, так как они будут потеряны, когда вы выполните другое регулярное выражение в коде замены.

117
задан Arkaitz Jimenez 5 May 2009 в 14:15
поделиться

7 ответов

При написании класса C ++ уместно подумать, будет ли он

  1. Тип значения

    Копирование по значению, идентичность никогда не важна. Для него уместно быть ключом в std :: map. Например, класс "string" или класс "date" или класс "complex number". «Копировать» экземпляры такого класса имеет смысл.

  2. Тип сущности

    Идентичность важна. Всегда передается по ссылке, никогда не по значению. Часто вообще не имеет смысла «копировать» экземпляры класса. Когда это имеет смысл, полиморфный метод «клонирования» обычно более уместен. Примеры: класс Socket, класс Database, класс «policy», все, что будет «замыканием» на функциональном языке.

И pImpl, и чистый абстрактный базовый класс - это методы для уменьшения зависимости времени компиляции.

Однако я всегда использую pImpl только для реализации типов Value (тип 1), и только иногда, когда я действительно хочу минимизировать связывание и компиляцию. временные зависимости. Часто это не стоит беспокоиться. Как вы правильно заметили, есть больше синтаксических издержек, потому что вы должны писать методы пересылки для всех открытых методов. Для классов типа 2 я всегда использую чистый абстрактный базовый класс с соответствующими фабричными методами.

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

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

61
ответ дан 24 November 2019 в 02:08
поделиться

Указатель на реализацию , как правило, скрывает детали структурной реализации. Интерфейсы предназначены для реализации различных реализаций. Они действительно служат двум различным целям.

32
ответ дан 24 November 2019 в 02:08
поделиться

В моем понимании эти две вещи служат совершенно различным целям. Цель идиомы pimple состоит в том, чтобы дать вам представление о вашей реализации, чтобы вы могли делать такие вещи, как быстрые замены для сортировки.

Цель виртуальных классов заключается в том, чтобы допустить полиморфизм, т. Е. У вас есть неизвестный указатель к объекту производного типа, и когда вы вызываете функцию x, вы всегда получаете правильную функцию для любого класса, на который в действительности указывает базовый указатель.

Яблоки и апельсины действительно.

2
ответ дан 24 November 2019 в 02:08
поделиться

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

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

27
ответ дан 24 November 2019 в 02:08
поделиться

Существует очень реальная проблема с разделяемыми библиотеками, которую идиома pimpl обходит аккуратно, чего не могут чистые виртуалы: вы не можете безопасно изменять / удалять элементы данных членов класс, не заставляя пользователей класса перекомпилировать их код. Это может быть приемлемо при некоторых обстоятельствах, но не, например, для системных библиотек.

Чтобы подробно объяснить проблему, рассмотрите следующий код в вашей общей библиотеке / заголовке:

// header
struct A
{
public:
  A();
  // more public interface, some of which uses the int below
private:
  int a;
};

// library 
A::A()
  : a(0)
{}

Компилятор генерирует код в разделяемой библиотеке, который вычисляет адрес целого числа, которое должно быть инициализировано, чтобы иметь определенное смещение (вероятно, ноль в этом случае, потому что это единственный член) от указателя на объект A, который он знает как this .

На стороне пользователя кода новый A сначала выделит sizeof (A) байтов памяти, затем передаст указатель на эта память для конструктора A :: A () как , это .

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

8
ответ дан 24 November 2019 в 02:08
поделиться

Я искал ответ на тот же вопрос. После прочтения некоторых статей и некоторой практики я предпочитаю использовать "Чистые виртуальные интерфейсы классов" .

  1. Они более просты (это субъективное мнение). Идиома Pimpl заставляет меня чувствовать, что я пишу код "для компилятора", а не для "следующего разработчика", который будет читать мой код.
  2. Некоторые фреймворки для тестирования имеют прямую поддержку Mocking чистых виртуальных классов
  3. Это правда, что вам нужно чтобы фабрика была доступна извне. Но если вы хотите использовать полиморфизм: это тоже "за", а не "против". ... и простой метод фабрики не так уж сильно вредит

Единственный недостаток (я пытаюсь исследовать это) в том, что идиома pimpl могла бы быть быстрее

  1. когда прокси-вызовы инлайнятся, в то время как наследование обязательно требует дополнительного доступа к VTABLE объекта во время выполнения
  2. след памяти pimpl public-proxy-class меньше (вы можете легко сделать оптимизацию для более быстрого свопинга и других подобных оптимизаций)
16
ответ дан 24 November 2019 в 02:08
поделиться

Мы не должны забывать, что наследование сильнее, ближе сцепление, чем делегирование. Я бы также принял во внимание все вопросы, поднятые в ответах, при принятии решения, какие идиомы дизайна использовать при решении конкретной проблемы.

6
ответ дан 24 November 2019 в 02:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: