Чтобы использовать этот класс я должен перечислить те-же include. Хотя ни один из открытых членов не использует в параметрах и в возврате ни vector ни map или что-там там еще требующее дополнительных заголовочных файлов.
Хотелось бы использовать только #include "someclass.h" во всех местах где данный класс вызывается.
Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей?
Если SomeClass есть часть какой-то библиотеки, то получается, что чтобы использовать ее нужно перечислить кучу заголовочных файлов предназначенных "для внутреннего использования" внутри класса.
Sorry если вопрос глупый
[] С>Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей?
Включи их в stdafx.h. Не знаю на счет красивости, но скорость компиляции точно увеличит. А если нужно защититься, то в someclass.h можно написать:
#ifndef _VECTOR_
#error I need <vector> to be included in stdafx.h
#endif
[]
Re: Сокрытие не-public членов классов
От:
Аноним
Дата:
22.01.03 07:03
Оценка:
Так вроде это известная особенность С++ — просачивание реализации в интерфейс через private-часть объявления класса. Чтобы этого избежать, используются либо интерфейсы (абстрактные классы) + фабрики, либо классы-обертки, единственный private-член которых — указатель на класс-реализацию. Во втором случае делается неполное обявление класса-реализации. У Мейерса все это подробно описано. Здесь где-то рядом был вопрос о том, как попроще кодировать делегирование.
Здравствуйте, Сray, Вы писали:
С>Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей? С>Если SomeClass есть часть какой-то библиотеки, то получается, что чтобы использовать ее нужно перечислить кучу заголовочных файлов предназначенных "для внутреннего использования" внутри класса. С>Sorry если вопрос глупый
Используй идиому Pimpl.
///////////////////////////////////////////////////////////////////////////////
// DataMapper.h#pragma once
#include"Reference.h"class DataMapper : public Reference
{
public:
DataMapper();
~DataMapper();
// ...private:
std::auto_ptr<struct DataMapperImpl> _pimpl; // непрозрачный указатель на реализацию
};
Undefined behavior могло бы возникнуть, если бы я не определил деструктор у DataMapper. В этом случае компилятор сгенерировал бы деструктор по-умолчанию в каждом объектнике, пользующем DataMapper, что и было бы причиной undefined behavior.
С>Чтобы использовать этот класс я должен перечислить те-же include. Хотя ни один из открытых членов не использует в параметрах и в возврате ни vector ни map или что-там там еще требующее дополнительных заголовочных файлов. С>Хотелось бы использовать только #include "someclass.h" во всех местах где данный класс вызывается. С>Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей? С>Если SomeClass есть часть какой-то библиотеки, то получается, что чтобы использовать ее нужно перечислить кучу заголовочных файлов предназначенных "для внутреннего использования" внутри класса. С>Sorry если вопрос глупый
Вообще-то я всегда думал, что ежели в объявлении SomeClass используются vector, map и т.д, то в этом же заголовке ты и обязан писать #include <vector>, #include <map> и т.д. Других вариатов я просто не вижу, особенно, если дело касается библиотек. Твои коллеги, которые будут использовать SomeClass, даже задумываться не должны, что кроме #include "someclass.h", они должны вызывать еще какой-то заголовок. А за "варианты покрасивие" нормальные руководители проекта отрывают руки. И правильно делают...
Здравствуйте, MaximE, Вы писали:
ME>Undefined behavior могло бы возникнуть, если бы я не определил деструктор у DataMapper. В этом случае компилятор сгенерировал бы деструктор по-умолчанию в каждом объектнике, пользующем DataMapper, что и было бы причиной undefined behavior.
открываем стандарт и смотрим пункт 17.4.3.6, а именно последнюю часть:
In particular, the effects are undefined in the following cases:
-if an incomplete type(3.9) is used as template argument when instanting a template component
Здравствуйте, grs, Вы писали:
grs>А за "варианты покрасивие" нормальные руководители проекта отрывают руки.
Вопервых "нормальные руководители" вообще не должны лазить по исходникам : это — не их парафия, их задача — правильно сделать постановку задачи и, может быть в некоторых случаях, предоставить программисту открытый интерфейс реализуемого им класса.
grs> И правильно делают...
а во вторых, если уж "нормальные руководители" начали лазить по коду, то незнание патерна(или как это правильно называеться) pimpl вообще ставит под сомнение их уровень квалификации
Здравствуйте, ssm, Вы писали:
ssm>Здравствуйте, MaximE, Вы писали:
ME>>Undefined behavior могло бы возникнуть, если бы я не определил деструктор у DataMapper. В этом случае компилятор сгенерировал бы деструктор по-умолчанию в каждом объектнике, пользующем DataMapper, что и было бы причиной undefined behavior.
ssm>открываем стандарт и смотрим пункт 17.4.3.6, а именно последнюю часть:
ssm>In particular, the effects are undefined in the following cases:
ssm>-if an incomplete type(3.9) is used as template argument when instanting a template component
ssm>что и имеет место в приведенном тобой коде
Это так. Но пользователем этой структуры является только DataMapper. В *.cpp DataMapperImpl полностью определен и вызов ~auto_ptr<DataMapperImpl> происходит только из определенного деструктора DataMapper, что не приводит к неопределенному поведению.
Это тоже самое, как если бы я написал так:
class DataMapper : public Reference
{
public:
DataMapper();
~DataMapper();
private:
//const std::auto_ptr<struct DataMapperImpl> _pimpl;struct DataMapperImpl* _pimpl;
};
ME>Это так. Но пользователем этой структуры является только DataMapper. В *.cpp DataMapperImpl полностью определен и вызов ~auto_ptr<DataMapperImpl> происходит только из определенного деструктора DataMapper, что не приводит к неопределенному поведению.
это неимеет никакого значения, стандарт в этом плане — неумолим. Нельзя, значит нельзя
ME>Это тоже самое, как если бы я написал так: ME> //const std::auto_ptr<struct DataMapperImpl> _pimpl; ME> struct DataMapperImpl* _pimpl;
вот если бы ты поступил так, то сделал бы в точности как писал Саттер
ME>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке
Здравствуйте, ssm, Вы писали:
ME>>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке
ssm>да он у меня на столе в бумажном виде лежит
Тогда ты, должно быть, туда не заглядывал.
Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.
Здравствуйте, Сray, Вы писали:
С>Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей?
Не знаю, насколько красив мой вариант, но когда-то (на "чистом" C) я поступал следующим образом:
#ifndef RETAIL
#include"header1.h"#include <header2.h>
struct MARC_RECORD
{
int field1;
char *field2;
};
#else
struct MARC_RECORD
{
int unused;
}
#endif
typedef struct MARC_RECORD *HMARC;
int marc_get_field1 (HMARC mrc);
Перед выдачей marc.h "на гора" он пропускается через программу ifdef:
ifdef -DRETAIL ./marc.h -o ../retail/marc.h
Думается, метод применим и в случае C++:
class SomeClass
{
public:
SomeClass();
virtual ~SomeClass();
int DoSomething(int);
#ifndef RETAIL
private:
vector<int> m_V;
map<int,int> m_M;
// etc...#endif
};
Основной недостаток данного метода для меня -- [пользователю] невозможно создать объект на стеке или в статической переменной. Точнее говоря, чтобы это стало возможным, нужно "добивать" фиктивную структуру до правильного размера.
ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.
О какой книге идет речь ? Интересно почитать. (или ссылку).
Здравствуйте, MaximE, Вы писали:
ME>Тогда ты, должно быть, туда не заглядывал. ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.
а еще и на 165 стр.
Ну тогда получаеться, что либо Герб незнает о таком пункте стандарта (что скорее всего врядли), либо знает и умышленно скрывает .
Ведь ясно в стандарте написано, что нельзя так делать. Как же быть
Что интерестно скажет Павел Кузнецов по этому поводу? Похожая тема поднималась уже здесь
Здравствуйте, ssm, Вы писали:
ssm>Ну тогда получаеться, что либо Герб незнает о таком пункте стандарта (что скорее всего врядли), либо знает и умышленно скрывает . ssm>Ведь ясно в стандарте написано, что нельзя так делать. Как же быть
Есть еще вариант, что ты прочитал фразу:
-if an incomplete type(3.9) is used as template argument when instanting a template component
но не удосужился узнать, что же такое "instanting a template".
Смотри 14.7 Template instantiation and specialization
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, ssm, Вы писали:
ME>>>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке
ssm>>да он у меня на столе в бумажном виде лежит
ME>Тогда ты, должно быть, туда не заглядывал. ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.
Здравствуйте, MaximE, Вы писали:
ME>Есть еще вариант, что ты прочитал фразу: ME>
ME>-if an incomplete type(3.9) is used as template argument when instanting a template component
Если ты читал это, то почему спрашиваешь?
ME>но не удосужился узнать, что же такое "instanting a template".
ME>Смотри 14.7 Template instantiation and specialization
Если ты удосужился узнать, что же такое "instanting a template", то может просвятишь меня когда будет инстанцироваться std::auto_ptr<DataMapperImpl> в твоем случае? Насколько я понимаю это происходит в клиентском коде:
#include"DataMapper.h"int main(){
DataMapper dm; //я думаю что здесь, хочешь сказать, что в этой точке DataMapperImpl not incomplete type ?
...
}
ssm>#include"DataMapper.h"
ssm>int main(){
ssm> DataMapper dm; //я думаю что здесь, хочешь сказать, что в этой точке DataMapperImpl not incomplete type ?
ssm>...
ssm>}
Кажется я допер сам
инстанцирование происходит в конструкторе DataMapper, а именно: