Свойства "в стиле VB" невозможно заменить перегрузкой оператора присваивания
и приведения типа. Если в классе содержится 10 свойств типа int, мы
неизбежно заходим в тупик. Что касается полезности этой концепции, она
признана многими разработчиками компонентно-ориентированных средств
разработки (кроме VB есть Delphi и BCB, в которые свойства вводились отнюдь
не только для поддержки COM, свойства есть в новом языке C# от Микрософт и
т. д.). Конечно, свойства - не революция. Вместо них можно использовать пару
методов Set/Get. Но они делают смысл происходящего в программе понятнее:
wnd.style |= WS_VISIBLE;
вместо
wnd.SetStyle(wnd.GetStyle() | WS_VISIBLE);
Кроме того, они развивают концепцию сокрытия деталей реализации от
пользователя класса: для него свойство выглядит как обычная переменная-член,
и он даже не догадывается, что для её реализации используются функции. Не
секрет, что многие программисты не любят методы Set/Get и продолжают
использовать открытые члены, несмотря на все призывы Страуструпа и иже с
ним. Даже в книгах по программированию этот "неправильный" подход
встречается сплошь и рядом. Свойства позволяют найти компромисс между этим
чисто человеческим нежеланием и важными принципами ООП. В выигрыше
оказываются все.
Что касается реализации свойств с С++, здесь перед нами встают проблемы.
Если вопрос портирования прграммы для нас не актуален, и мы ограничиваемся
VC, я не вижу смысла игнорировать его расширенные возможности. Использование
__deсlspec(property) в этом случае является исключительно делом вкуса
программиста. Принципиальных возражений против его использования нет.
А вот "самодельные" свойства приносят в жертву эффективность программы, и
поэтому мы должны или отказаться от них, или улучшить, убрав лишние затраты.
Вот пример возможного улучшения.
#include <stddef.h>
//***************************
// Макрос для свойства
#define PROPERTY(ownertype, proptype, prop, getfunc, setfunc)
\
class __property##prop
\
{
\
public:
\
operator proptype()
\
{
\
return ((ownertype *)((char *)this - offsetof(ownertype,
prop)))->getfunc(); \
}
\
void operator=(proptype data)
\
{
\
((ownertype *)((char *)this - offsetof(ownertype,
prop)))->setfunc(data); \
}
\
};
\
friend __property##prop;
\
__property##prop prop
//***************************
// Пример использования
class CValue
{
private:
char m_value;
public:
int get_Value()
{
return m_value; // Или более сложная логика
}
void put_Value(int value)
{
m_value = value; // Или более сложная логика
}
// Свойство Value типа int, использующее функции
// get_Value и put_Value класса CValue
PROPERTY(CValue, int, Value, get_Value, put_Value);
};
int main(int argc, char* argv[])
{
CValue val;
/*
Здесь вызывается оператор присваивания переменной-члена val.Value,
и, следовательно, функция val.put_Value()
*/
val.Value = 50;
/*
Здесь вызывается оператор приведения типа переменной-члена val.Value,
и, следовательно, функция val.get_Value()
*/
int z = val.Value;
return 0;
}
В этом случае ликвидируются как временные затраты (все функции класса
__property##prop являются встроенными), так и затраты по памяти (к
сожалению, только теоретически, так как VC "не умеет" создавать объекты
класса нулевой длины). Кроме того, следует заметить, что полученное свойство
не является полным эквивалентом __declspec. Например, нельзя написать
val.Value += 50;
Этот недостаток присущ и реализации в выпуске 43. Чтобы устранить его,
придётся перегружать множество операторов, а потом, возможно, отлавливать
множество тонких ошибок. Вот почему я считаю, что "самодельные" свойства
представляют скорее теоретический интерес. Это, однако, не повод
провозглашать ненужной саму концепцию свойств, аргументируя это мощью и
могуществом языка C++, который в них не нуждается.
- Александр Шаргин
Для этой цели служит функция SQLConfigDataSource(). Она
позволяет создать пользовательский или системный источник данных (DSN -
DataSource Name). Эта же функция позволяет модифицировать или удалить DSN.
BOOL SQLConfigDataSource(
HWND hwndParent,
WORD fRequest,
LPCSTR lpszDriver,
LPCSTR lpszAttributes);
Здесь hwndParent - хэндл окна, которому будут направляться
сообщения об ошибках (в случае использования NULL эти сообщения будут
подавляться), fRequest - тип выполняемого действия (к примеру,
ODBC_ADD_DSN - добавить пользовательский DSN, ODBC_ADD_SYS_DSN - добавить
системный DSN), lpszDriver - точное имя драйвера ODBC, так, как
оно выглядит в диалоге настройки ODBC DSN, например "Microsoft Access Driver
(*.mdb)" или "SQL Server". Строка lpszAttributes содержит
основные параметры подключения к источнику данных:
DSN - название создаваемого источника данных
UID - имя пользователя
DATABASE - имя базы данных
PWD - пароль для подключения
Параметры разделены между собой символом '\0', конец строки отмечается
дополнительным символом '\0'.
Обязательным является имя DSN. Все остальные параметры могут быть запрошены
при подключении к источнику данных. Хотя различные драйверы ODBC в этом
отношении могут вести себя по-разному - например, для драйвера MS SQLServer
обязательным параметром также является и имя сервера.
///////////////////////////////////////////////////////////
//// Пример создания источника данных для
// ODBC драйвера для Microsoft Excel 97
//
#include <windows.h>
#include <odbcinst.h>
#pragma comment(lib, "odbccp32")
#pragma comment(lib, "user32")
void main()
{
char* driver = "Microsoft Excel Driver (*.xls)";
char* params = "DSN=MyTable\0DefaultDir=D:\\Document\0""DBQ=D:\\Document\\MyTable.xls\0";
// Создадим пользовательский DSN
SQLConfigDataSource(NULL, ODBC_ADD_DSN, driver, params);
}
Надеюсь, для Вас не будет слишком большим сюрпризом узнать, что всю
информацию об источниках данных и драйверах ODBC Windows хранит в реестре. А
если быть совсем точным, то в ключах
Информацию о том, как правильно заполнять строку params, можно
извлечь самостоятельно, создавая при помощи ODBC-администратора источники данных
для различных драйверов Вашей системы и анализируя состав параметров и
присвоенные им значения ключей реестра, относящихся к созданным источникам.
Надеюсь также, что не сильно шокирую Вас, если скажу, что приведенный выше
пример был написан именно так.