Статическая инициализация структур
{
char *s;
double d;
};
struct ZRV
{
int nomer;
char *naim;
int nparam;
ZRVParam *param;
double (*func)(...);
};
Первую структуру - возможно. Например,
{"среднее",0.0}, {"стандартное отклонение",1.0}
}
Но вот вторая - вопрос. Она должна включать указатель на переменную или массив типа ZRVParam и указатель на функцию.
Функции написаны, но проинициализировать вторую структуру не удается.
{
char *s;
double d;
};
struct ZRV
{
int nomer;
char *naim;
int nparam;
ZRVParam *param;
double (*func)(...);
};
double func0(...) { return 0; }
double func1(...) { return 0; }
ZRVParam NormParam[] ={
{"среднее",0.0},
{"стандартное отклонение",1.0}
};
ZRV zrv[] = {
{0, "0", 0, NormParam, func0},
{1, "1", 1, NormParam, func1}
};
А вообще, код некрасивый...
У меня всё инициализируется:
{
char *s;
double d;
};
struct ZRV
{
int nomer;
char *naim;
int nparam;
ZRVParam *param;
double (*func)(...);
};
double func0(...) { return 0; }
double func1(...) { return 0; }
ZRVParam NormParam[] ={
{"среднее",0.0},
{"стандартное отклонение",1.0}
};
ZRV zrv[] = {
{0, "0", 0, NormParam, func0},
{1, "1", 1, NormParam, func1}
};
А вообще, код некрасивый...
Как будет красивее?
Как будет красивее?
Гы.. А вот не знаю...
(что-то вопрос в тупик поставил)
Всё зависит от цели.
Для начала я бы сделал не структуры, а классы, и инициализировал через конструкторы. Это было бы очевиднее.
Потом убрал бы использование функция с троеточием, сделал бы функции с конкретным набором параметров, возможно шаблонные. Возможно, что это будут и не функции, а функторы.
А ZRV обязательно должен ссылаться на ZRVParam?
Он не может просто агрегировать эту структуру?
Ну в общем дальше сложно сказать. Просто, такая статическая инициализации выглядит ужасающе. И мне кажется, может привести к неявным ошибкам.
Может есть смысл создать класс-контейнер для всех ZRV, и в его конструкторе все инициализировать?
Гы.. А вот не знаю...
(что-то вопрос в тупик поставил)
Всё зависит от цели.
Для начала я бы сделал не структуры, а классы, и инициализировал через конструкторы. Это было бы очевиднее.
Потом убрал бы использование функция с троеточием, сделал бы функции с конкретным набором параметров, возможно шаблонные. Возможно, что это будут и не функции, а функторы.
А ZRV обязательно должен ссылаться на ZRVParam?
Он не может просто агрегировать эту структуру?
Ну в общем дальше сложно сказать. Просто, такая статическая инициализации выглядит ужасающе. И мне кажется, может привести к неявным ошибкам.
Может есть смысл создать класс-контейнер для всех ZRV, и в его конструкторе все инициализировать?
Там на самом деле все просто. Есть набор функций - они генерируют случайную величину, подчиненную определенному закону распределения вероятностей (ЗРВ) (например, нормальный, Пуассона). Все эти функции возвращают вещественное число типа double. Набор параметров для различных ЗРВ свой. Например, чтобы сгенерировать нормальную случ.величину, нужно задать два вещ. параметра (среднее, станд.отклонение), чтобы сгенерировать случ.величину Пуассона - один параметр (лямбда).
Все эти функции есть, известно число передаваемых параметров, их названия, просто для удобства я попытался записать это в одну структуру.
В структуру ZRVParam - название параметра и его значение, в струткуру ZRV - название генерируемого ЗРВ (naim), число параметров (nparam), указатель на структуру ZRVParam с числом элементов nparam, и указатель на функцию генерирующую данный ЗРВ. Вот например, как это выглядит для нормального ЗРВ и ЗРВ Пуассона
{"среднее",0.0},
{"стандартное отклонение",1.0}
};
const ZRVParam Param2[] = {{"лямбда",0}};
const ZRV zrv[]= {
{1,"Нормальное",sizeof(Param1)/sizeof(Param1[0]),Param1,(double (*)(...))MGAUSS},
{2,"Пуассона",sizeof(Param2)/sizeof(Param2[0]),Param2,(double (*)(...))MPUAS}
};
Функции MGAUSS, MPUAS описаны так
// SIG,ДEЙCTBИTEЛЬHЫЙ,>0,CTAHДAPTHOE OTKЛOHEHИE
double MGAUSS(double s, double sig);
// p - параметр "лямбда"
double MPUAS(double p)
Например:
{
public:
virtual ~ZVR() {}
double getRndValue() = 0;
const char* getName() = 0;
list<ZRVParam> getParams() = 0;
};
А далее для каждого закона распределения отнаследовать свой класс:
{
public:
NormalZVR(double standardDeviation, double average)
: standardDeviation(standardDeviation),
average(average) {}
virtual ~NormalZVR() {}
double getRndValue() { return double MGAUSS(average, standardDeviation); }
const char* getName() { return "Нормальное"; }
list<ZRVParam> getParams() {
list<ZRVParam> params;
params.push_back( ZRVParam("стандартное отклонение", standardDeviation) );
params.push_back( ZRVParam("среднее", average) );
return params;
}
private:
double standardDeviation;
double average;
};
class PoissonZVR :public ZVR
{
public:
PoissonZVR(double lambda) :lambda(lambda) {}
virtual ~PoissonZVR() {}
double getRndValue() { return MPUAS(lambda); }
const char* getName() { return "Пуассона"; }
list<ZRVParam> getParams() {
list<ZRVParam> params;
params.push_back( ZRVParam("лямбда", lambda) );
return params;
}
private:
double lambda;
};
Конечно, коллекции параметров можно возвращать и др. способами, list я привел, как пример.
Если надо объявлять статический массив различных законов с различными параметрами, то можно добавить для удобства ещё один класс (умный указатель):
{
public:
template<class T>
PtrZVR(T& ref) :ptr(new T(ref)) {}
~PtrZVR() { delete ptr;}
ZVR& operator*() const { return (*ptr); }
ZVR* operator->() const { return (&**this); }
private:
ZVR* const ptr;
};
Теперь можно создавать статические массивы:
А так можно вывести названия законов и результаты:
{
for(int i=0; i<sizeof(zrv)/sizeof(zrv[0]); ++i) {
std::cout << zrv->getName() << " : " << zrv->getRndValue() << std::endl;
}
return 0;
}
double getRndValue() = 0;
Компилятор ругается. Если написать
virtual double getRndValue() = 0;
то все нормально, но зачем писать =0;?
Зачем нужен "умный укзатель"?
Смарт поинтеры нужны для предотвращения ликимемори. Он автоматом уничтожается при выходе из блока в котором он объявлен.
В принципе в Студии есть уже клас смартпоинтера - auto_ptr.
Почему в определениии класса ZRV обязательно пишется
double getRndValue() = 0;
Компилятор ругается. Если написать
virtual double getRndValue() = 0;
то все нормально, но зачем писать =0;?
Ссори, я очепятался. Конечно, нужно написать вначале virtual.
ZVR - это интерфейс, т.е. чисто абстрактный класс, который определяет лишь интерфейс наследников, но не имеет реализации. Поэтому и virtual double getRndValue() = 0;
Смарт поинтеры нужны для предотвращения ликимемори. Он автоматом уничтожается при выходе из блока в котором он объявлен.
В принципе в Студии есть уже клас смартпоинтера - auto_ptr.
Автоматическое уничтожение объектов - это лишь одна из функций умных указателей.
А вообще умные указатели - это классы расширяющие функциональность обычных указателей. Т.е. внешне они выглядят, как указатели, но на самом деле совершают некоторые полезные действия с объектами, на которые ссылаются.
В моём примере умный указатель позволяет скопировать объект. Без него тебе бы пришлось сначала создать глобальные объекты, а потом занести указатели на них в массив:
const static PoissonZVR(0.0) poissonZVR(0.0);
ZVR* const zrv[]= { (ZVR*)&normalZVR, (ZVR*)&poissonZVR };
С умным же указателем все очевиднее и приятнее на вид:
А есть какая-либо литература по "умным указателям" и новым технологиям программирования. В Подбельском не встречал подобного. Может быть, это у Буча есть?
Эти книги одно и то же?
Да.
По второй ссылке у меня быстрее скачалась.