Сокрытие не-public членов классов
От: Сray  
Дата: 22.01.03 02:03
Оценка:
Предположим, что в неком заголовочном файле "someclass.h" содержится такая запись:
class SomeClass
{
public:
    SomeClass();
    virtual ~SomeClass();
    int DoSomething(int);
private:
    vector<int> m_V;
    map<int,int> m_M;
    // etc...
};

В файле "someclass.cpp" тогда должно быть
#include <vector>
#include <map>
#include <evrething> // :-)
#include "someclass.h"


Чтобы использовать этот класс я должен перечислить те-же include. Хотя ни один из открытых членов не использует в параметрах и в возврате ни vector ни map или что-там там еще требующее дополнительных заголовочных файлов.
Хотелось бы использовать только #include "someclass.h" во всех местах где данный класс вызывается.
Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей?
Если SomeClass есть часть какой-то библиотеки, то получается, что чтобы использовать ее нужно перечислить кучу заголовочных файлов предназначенных "для внутреннего использования" внутри класса.
Sorry если вопрос глупый
Re: Сокрытие не-public членов классов
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 22.01.03 03:01
Оценка:
Здравствуйте, Сray, Вы писали:

[]
С>Я, конечно, понимаю, что можно все необходимые 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-член которых — указатель на класс-реализацию. Во втором случае делается неполное обявление класса-реализации. У Мейерса все это подробно описано. Здесь где-то рядом был вопрос о том, как попроще кодировать делегирование.
Re: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 22.01.03 08:01
Оценка: 2 (1)
Здравствуйте, С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; // непрозрачный указатель на реализацию
};



///////////////////////////////////////////////////////////////////////////////
// DataMapper.cpp

#include "stdafx.h"
#include "DataMapper.h"

using namespace ADODB;
using namespace std;

///////////////////////////////////////////////////////////////////////////////

struct DataMapperImpl
{
    DataMapperImpl() : _connection(__uuidof(Connection))
    {
        _connection->Open(sqlConnection, _bstr_t(), _bstr_t(), adConnectUnspecified);
    };

    _ConnectionPtr _connection;
};

///////////////////////////////////////////////////////////////////////////////

DataMapper::DataMapper()
    :    _pimpl(new DataMapperImpl)
{
}

///////////////////////////////////////////////////////////////////////////////


Подробнее: Compilation Firewalls
Re[2]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 22.01.03 14:14
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>std::auto_ptr<struct DataMapperImpl> _pimpl; // непрозрачный указатель на реализацию


По стандарту, это может привести ... к форматированию жесткого диска Подробней здесь
Автор: Павел Кузнецов
Дата: 08.01.03
Re[3]: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 22.01.03 16:18
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Здравствуйте, MaximE, Вы писали:


ssm>
ME>>std::auto_ptr<struct DataMapperImpl> _pimpl; // непрозрачный указатель на реализацию
ssm>


ssm> По стандарту, это может привести ... к форматированию жесткого диска Подробней здесь
Автор: Павел Кузнецов
Дата: 08.01.03


Undefined behavior могло бы возникнуть, если бы я не определил деструктор у DataMapper. В этом случае компилятор сгенерировал бы деструктор по-умолчанию в каждом объектнике, пользующем DataMapper, что и было бы причиной undefined behavior.
Re: Сокрытие не-public членов классов
От: grs Россия  
Дата: 22.01.03 16:29
Оценка:
Здравствуйте, Сray, Вы писали:

С>Предположим, что в неком заголовочном файле "someclass.h" содержится такая запись:

С>
С>class SomeClass
С>{
С>public:
С>    SomeClass();
С>    virtual ~SomeClass();
С>    int DoSomething(int);
С>private:
С>    vector<int> m_V;
С>    map<int,int> m_M;
С>    // etc...
С>};
С>

С>В файле "someclass.cpp" тогда должно быть
С>
С>#include <vector>
С>#include <map>
С>#include <evrething> // :-)
С>#include "someclass.h"
С>


С>Чтобы использовать этот класс я должен перечислить те-же include. Хотя ни один из открытых членов не использует в параметрах и в возврате ни vector ни map или что-там там еще требующее дополнительных заголовочных файлов.

С>Хотелось бы использовать только #include "someclass.h" во всех местах где данный класс вызывается.
С>Я, конечно, понимаю, что можно все необходимые include засунуть в "someclass.h". Собственно, так обычно и делаю. Но может есть какие-нибуть другие варианты покрасивей?
С>Если SomeClass есть часть какой-то библиотеки, то получается, что чтобы использовать ее нужно перечислить кучу заголовочных файлов предназначенных "для внутреннего использования" внутри класса.
С>Sorry если вопрос глупый

Вообще-то я всегда думал, что ежели в объявлении SomeClass используются vector, map и т.д, то в этом же заголовке ты и обязан писать #include <vector>, #include <map> и т.д. Других вариатов я просто не вижу, особенно, если дело касается библиотек. Твои коллеги, которые будут использовать SomeClass, даже задумываться не должны, что кроме #include "someclass.h", они должны вызывать еще какой-то заголовок. А за "варианты покрасивие" нормальные руководители проекта отрывают руки. И правильно делают...
Re[4]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 22.01.03 16:34
Оценка:
Здравствуйте, 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


что и имеет место в приведенном тобой коде
Re[2]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 22.01.03 16:45
Оценка:
Здравствуйте, grs, Вы писали:

grs>А за "варианты покрасивие" нормальные руководители проекта отрывают руки.


Вопервых "нормальные руководители" вообще не должны лазить по исходникам : это — не их парафия, их задача — правильно сделать постановку задачи и, может быть в некоторых случаях, предоставить программисту открытый интерфейс реализуемого им класса.

grs> И правильно делают...


а во вторых, если уж "нормальные руководители" начали лазить по коду, то незнание патерна(или как это правильно называеться) pimpl вообще ставит под сомнение их уровень квалификации
Re[5]: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 22.01.03 16:55
Оценка:
Здравствуйте, 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;
};



///////////////////////////////////////////////////////////////////////////////

struct DataMapperImpl
{
    DataMapperImpl() : _connection(__uuidof(Connection))
    {
        _connection->Open(sqlConnection, _bstr_t(), _bstr_t(), adConnectUnspecified);
    };

    _ConnectionPtr _connection;
};

///////////////////////////////////////////////////////////////////////////////

DataMapper::DataMapper()
    :    _pimpl(new DataMapperImpl)
{
}

///////////////////////////////////////////////////////////////////////////////

DataMapper::~DataMapper()
{
    delete _pimpl;
}


Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке
Re[6]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 22.01.03 17:06
Оценка:
Здравствуйте, MaximE, Вы писали:


ME>Это так. Но пользователем этой структуры является только DataMapper. В *.cpp DataMapperImpl полностью определен и вызов ~auto_ptr<DataMapperImpl> происходит только из определенного деструктора DataMapper, что не приводит к неопределенному поведению.


это неимеет никакого значения, стандарт в этом плане — неумолим. Нельзя, значит нельзя

ME>Это тоже самое, как если бы я написал так:

ME> //const std::auto_ptr<struct DataMapperImpl> _pimpl;
ME> struct DataMapperImpl* _pimpl;

вот если бы ты поступил так, то сделал бы в точности как писал Саттер

ME>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке


да он у меня на столе в бумажном виде лежит
Re[7]: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 22.01.03 18:59
Оценка:
Здравствуйте, ssm, Вы писали:

ME>>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке


ssm>да он у меня на столе в бумажном виде лежит


Тогда ты, должно быть, туда не заглядывал.
Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.
Re: Сокрытие не-public членов классов
От: Алексей Владимирович Миронов Россия  
Дата: 23.01.03 01:17
Оценка:
Здравствуйте, С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
};


Основной недостаток данного метода для меня -- [пользователю] невозможно создать объект на стеке или в статической переменной. Точнее говоря, чтобы это стало возможным, нужно "добивать" фиктивную структуру до правильного размера.
Re[8]: Сокрытие не-public членов классов
От: romasha Украина  
Дата: 23.01.03 06:36
Оценка:
ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.

О какой книге идет речь ? Интересно почитать. (или ссылку).
Re[9]: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 23.01.03 07:41
Оценка:
Здравствуйте, romasha, Вы писали:

R>О какой книге идет речь ? Интересно почитать. (или ссылку).


Herb Sutter "Exceptional C++". Практически все содержание книги лежит у него на сайте в разделе Guru of the Week
Re[8]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 23.01.03 07:45
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Тогда ты, должно быть, туда не заглядывал.

ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.

а еще и на 165 стр.

Ну тогда получаеться, что либо Герб незнает о таком пункте стандарта (что скорее всего врядли), либо знает и умышленно скрывает .
Ведь ясно в стандарте написано, что нельзя так делать. Как же быть
Что интерестно скажет Павел Кузнецов по этому поводу? Похожая тема поднималась уже здесь
Автор: ssm
Дата: 08.01.03
, но ПК в своем ответе дал точно понять что так делать нельзя, если следовать стандарту, а тут Герб...
Так кому же верить?
Re[9]: Сокрытие не-public членов классов
От: MaximE Великобритания  
Дата: 23.01.03 08:06
Оценка:
Здравствуйте, 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
Re[8]: Сокрытие не-public членов классов
От: alexkro  
Дата: 23.01.03 09:24
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Здравствуйте, ssm, Вы писали:


ME>>>Рекоммендую, все-таки, почитать Саттера по вышеприведенной ссылке


ssm>>да он у меня на столе в бумажном виде лежит


ME>Тогда ты, должно быть, туда не заглядывал.

ME>Возьми же наконец его со стола и открой на стр.267 "Упаковка членов-указателей" и затем на стр.271 "Оболочка указателей-членов" (так перевела некто Красикова). Там как раз обсуждается использование Pimpl и auto_ptr.

Я думаю, лучше почитать здесь: http://www.gotw.ca/gotw/062.htm
Re[10]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 23.01.03 09:49
Оценка:
Здравствуйте, 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 ?
...
}
Re[11]: Сокрытие не-public членов классов
От: ssm Россия  
Дата: 23.01.03 09:57
Оценка:
Здравствуйте, ssm, Вы писали:


ssm>#include "DataMapper.h"

ssm>int main(){

ssm>  DataMapper dm;  //я думаю что здесь, хочешь сказать, что в этой точке DataMapperImpl not incomplete type ?
ssm>...
ssm>}


Кажется я допер сам
инстанцирование происходит в конструкторе DataMapper, а именно:

DataMapper::DataMapper()
    :    _pimpl(new DataMapperImpl)
{
}


а здесь то DataMapperImpl уже точно определен.
Если я неправ, то поправь
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.