Почему закрытые члены / методы определены в интерфейсе? - PullRequest
19 голосов
/ 08 сентября 2011

Меня всегда смущал тот факт, что большинство языков ООП (или, скорее, C ++) заставляют вас определять частные методы / члены в интерфейсе (под интерфейсом я имею в виду объявление класса - кажется, я был сбит с толку).Разве это не показывает детали реализации класса и идет вразрез с идеей инкапсуляции?

Есть ли веская причина для этого, что я пропустил?

Ответы [ 6 ]

12 голосов
/ 08 сентября 2011

Для C ++ это проблема реализации.

Компилятор C ++ должен иметь возможность генерировать код, который использует класс, только просматривая объявление класса, а не реализацию. Одна очень важная вещь, которая требуется компилятору, - это размер экземпляра класса, потому что C ++, среди прочего, обрабатывает подобъекты в объектах путем встраивания, а не хранения ссылки на отдельный объект. Чтобы иметь возможность построить объект (например, struct X { Y y; Z z; }), размер всех подобъектов (например, Y и Z) должен быть известен заранее.

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

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

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

8 голосов
/ 08 сентября 2011

C ++ - единственный язык, который я знаю, который делает это; В частности, существует несколько функциональных языков, которые строго разделяют объявление открытых и закрытых интерфейсов. И обратите внимание, что C ++ делает разницу между объявлением и определением : вам нужно только объявить частных функций в интерфейсе, а не определить их .

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

Я подозреваю, что вам также нужно объявлять не виртуальные функции публично в C ++, чтобы поддерживать их согласованность: в противном случае вам придется объявлять разные функции в разных местах, в зависимости от того, являются ли они публичными и / или виртуальными. .

Вы можете обойти это ограничение, используя идиому тела ручки (также известную своим косметически менее привлекательным названием «PIMPL»), но это добавляет собственную сложность решению.

2 голосов
/ 08 сентября 2011

В частном случае C ++ одна из причин заключается в том, что объявление всех виртуальных функций - будь то общедоступных или приватных - необходимо для создания таблицы виртуальных указателей.Вероятно, та же причина относится и к другим языкам.

Это не противоречит идее инкапсуляции, частные методы / члены не являются частью интерфейса PUBLIC , поэтому данные остаются инкапсулированными.Кроме того, модификаторы public / private обеспечивают только видимость.

2 голосов
/ 08 сентября 2011

Существует два значения, в которых слово интерфейс используется в C ++: интерфейс ООП и объявление типа.

Интерфейс ООП используется для инкапсуляции и полиморфизма. В C ++ это обычно реализуется с чистыми абстрактными классами. Идиома PIMPL также используется для инкапсуляции. В любом случае потребителю показываются только открытые члены типа, и он получает доступ к частной реализации через уровень косвенности. Java и C # поддерживают явные интерфейсы и оба ограничивают их членов публичным доступом.

Объявления типов требуются в C ++ из-за его модели связывания. Объявление типа не является его интерфейсом в смысле ООП, но поскольку объявление типа должно быть включено перед использованием, разъединение реализации становится более желательным. Для этого мы используем интерфейсы ООП, как описано выше. Не было бы необходимости скрывать частные детали реализации от объявления типа, если бы только модули поддерживали C ++. Поддержка модуля была предложена для C ++ 11, но из-за временных ограничений, установленных для включения в будущий TR.

0 голосов
/ 25 сентября 2014

Есть много способов решить эту проблему в C ++.

Вы можете использовать фабричный шаблон , чтобы скрыть приватные члены и методы для пользователей. Вам нужно создать abstract class в качестве вашего API или интерфейса, а затем реализовать свой класс в подклассе и объявить там все свои закрытые члены, таким образом, ваши пользователи не будут видеть ваши закрытые члены и реализации.

0 голосов
/ 08 сентября 2011

Как вы получили такой вывод? Я не нашел ООП языков, которые заставляют меня делать это. Для C ++ причина, по которой люди определяют методы в интерфейсе, - это встроенная цель. Что касается участников, то это потому, что вы не можете определить это где-либо еще, и это относится ко всем видениям, а не только к частным.

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