Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: С++. Ошибка в private-контрукторе
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
jorikdima
Добрый день.

Наткнулся на непонятную для меня проблему. Сначала делал для MSP430, но под Win на Visual Studio тоже самое, поэтому вопрос связан с общими понятиями C++.
Код
class A
{
public:
    static A* Init(int i);
private:
    A(int u);
    int r;
};

A* A::Init(int i)
{
    A(i);                   //[b]вот тут ошибка[/b]
}

A::A(int u)
{
    r=u;
}

void main()
{
    A* p=A::Init(6);
}

Вот такой вот простецкий код. Хочу сделать private-constructor, так как надо сделать ограничение на количество создаваемых объектов. В статической функции Init провожу проверку (сдесь не написал для наглядности) и если условие выполняется, то вызываю коснструктор, то есть выделяю память.
И все у меня здорово, до тех пор пока конструктор был без параметров, все работало как надо. А вот при добавлении параметра к конструктору оба компилятра выдают какую-то неперевариваемую мной ошибку:
Код
1. redifinition of formal parameter i
2. "A": no appropriate default constructor available

не понимаю, почему он хочет дефолт-конструктор и почему переопределение переменной i?


PS
Модераторы, не первый раз уже думаю в какую часть форума писать подобные вопросы. Нет подфорума по общим вопросам программирования (или в системный уровень программирования писать???). Написал тут хотя понимаю - ЦОС непричем.

Спасибо.
makc
Приведите, пожалуйста, полный код, а то, например, такое:
Код
class A
{
public:
    static A* Init(int i);
private:
    A(int u);
    int r;
};

A* A::Init(int i)
{
    return new A(i);            
}

A::A(int u)
{
    r=u;
}

int main()
{
    A* p=A::Init(6);
    return (int)p;
}

у меня прекрасно компилируется и работает.
jorikdima
c new у меня тоже компилируется. blink.gif
Но я изначально пишу для MSP430 а там без new надо.
Разве я не могу там вызвать конструктор.
Вот более похожий на оригинал код:
Код
class A
{
public:
    static A* Init(int i);
private:
    A(int u);
    static A* a[2];
    
};

A* A::a[2]={0};

A* A::Init(int i)
{
    if (i<2 && i>0 && a[i]==0)
    {        
        A(i);                       //если индекс объекта 0 или 1 и он еще не создан, то создаем
        return a[i];             //в переменной static A* a[2]; лежат адреса созданных объектов
    }
    return (A*)0;
}

A::A(int u)
{
    a[u]=this;
}

void main()
{
    A* p=A::Init(0);
}

Смысл идеи в следующем - подсчитывать количество созданных объектов и если выше порога не создавать, чтоб нельзя было A t[100]; написать.

PS Класс описывает работу UART, а у меня их всего два. )) Можно конечно самому себе сказать - не создавай третий и больше, но.. вобщем тут даже скорее любопытство, почему нельзя вот так?

написал и сам задал себе вопрос а почему c new нельзя???
Кстати с new и в ИАРе заработало. biggrin.gif

new - это ведь динамически выделяемая память в heap.
В чем будет разница по сравнению с обычным созданием объекта, а не через new и private конструктор?

Вообще применительно к embedded new нормально испоьзовать? Я вроде понимаю, что если динамически занимать и освобождать память то вроде Memory Management нужен, а если без delete, если только занимать?

Чето я подглюкиваю к вечеру blink.gif cranky.gif
Oldring
Очевидно, компилятор распарсивает эту строчку как определение локальной переменной с именем i типа A с конструктором умолчания.

Главная ошибка состоит в том, что прежде чем для объекта будет вызван какой-нибудь конструктор, под него должно быть где-то выделено место в памяти компьютера. Если объект создается динамически - это место выделяется оператором new. Операто new может быть переопределен нужным программисту образом - чтобы создавать объект не в куче, а где-то в другом месте. Где именно Вы его хотите разместить? Это главный вопрос для понимания происходящего.
jorikdima
Все что мне надо - это контроль количества созданных объектов. Мне не очень хочется усложнять себе жизнь и в первую очередь раздувать код (я и так этого предостаточно сделал на ровном месте) заботясь о расположении объекта в памяти. Пусть он располагается так, как будто он создается глобально. Ведь когда объект располагается глобально я не забочусь о его размещении, это делает компилятор. Тут хочу тоже самое, и без new. Может мои желания и странные. Удивляет собственно тот факт, почему если конструктор без параметров, то все работает как надо? blink.gif
Oldring
Цитата(jorikdima @ Jan 8 2007, 23:29) *
Все что мне надо - это контроль количества созданных объектов. Мне не очень хочется усложнять себе жизнь и в первую очередь раздувать код (я и так этого предостаточно сделал на ровном месте) заботясь о расположении объекта в памяти. Пусть он располагается так, как будто он создается глобально. Ведь когда объект располагается глобально я не забочусь о его размещении, это делает компилятор. Тут хочу тоже самое, и без new. Может мои желания и странные. Удивляет собственно тот факт, почему если конструктор без параметров, то все работает как надо? blink.gif


Если хотите контролировать количество создаваемых объектов - заведите в объекте статической поле типа int и считайте в нем в обычных конструкторе и деструкторе. Только все это от лукавого.
AndrewKirs
Цитата(jorikdima @ Jan 8 2007, 22:16) *
A* A::Init(int i)
{
A(i); //вот тут ошибка
}
Не совсем понимаю, что Вы тут хотели написать. Очевидно, создать статический экземпляр А? Скажем так:

A* A::Init(int i)
{
A a(i).
return &a;
}

Но ведь этот экземпляр создается в стеке функции и будет потерян после выхода из нее.

А вообще, по-моему, сама идея "некрасивая" - контролировать число объектов какого-то класса из самого этого класса. Я бы на Вашем месте вынес этот контроль на уровень выше:

class A
{
public:
A(){}
private:
A(int u){}
int r;
};

#define MAX_A_COUNT 2

class B{
private:
int iAcount;
A ArrayOfA[MAX_A_COUNT];
public:
B(){ iAcount = 0;}
A * CreateA();
};

A * B::CreateA()
{
if (iAcount >= MAX_A_COUNT) return 0;
return &ArrayOfA[iAcount++];
}

void main()
{
B b;
A * a1 = b.CreateA();
A * a2 = b.CreateA();
A * a3 = b.CreateA(); // a3 = 0, что и требовалось
}
jorikdima
Спасибо! Мне понравилась идея. Так и сделаю. Спасибо еще раз.
AndrewKirs
Всегда пожалуйста.
Pathfinder
Если ограничение на число экземпляров связано с сущностью, которую представляет класс, логичнее контролировать число экземпляров класса из самого класса. Это можно просто сделать например так:
Код
A::A()
{
/* Инициализация локальной статической
* переменной выполняется только один раз
* при вызове конструктора для первого объекта */
static int instance_counter = 0;
/* А вот эта операция будет выполняться при каждом вызове конструктора. */
instance_counter++;
if (instance > max_instance_count ) throw int();
}
AndrewKirs
Цитата(Pathfinder @ Feb 9 2007, 17:54) *
Если ограничение на число экземпляров связано с сущностью, которую представляет класс, логичнее контролировать число экземпляров класса из самого класса. Это можно просто сделать например так:
Код
A::A()
{
/* Инициализация локальной статической
* переменной выполняется только один раз
* при вызове конструктора для первого объекта */
static int instance_counter = 0;
/* А вот эта операция будет выполняться при каждом вызове конструктора. */
instance_counter++;
if (instance > max_instance_count ) throw int();
}
Воля Ваша, но некрасиво это как-то... Лучше, логичнее, когде работает один объект, а контролирует его другой. Разделение функций на уровне логики и на уровне кода. В конце концов, этот контролирующий класс можно сделать наследником контролируемого. То есть в моем примере вместо

class B{
...
};

будет

class B: public A{
...
};
Pathfinder
AndrewKirs,
считать число экземпляров объекта внутри реализации класса - довольно распространенное решение (пример - strings в STL), внешней программе как правило абсолютно не интересно знать, сколько на самом деле экземпляров существует - их количество используется только внутри класса.
В данном случае логичнее было бы не ограничивать количество экземпляров класса, а не позволять создать два экземпляра для одного и того же порта.
shreck
Может быть не совсем по теме вопроса, но хочется привести решение похожей задачи из классики.

Для того, чтобы ограничить количество создаваемых экземпляров класса одним объектом применяется идеология синглетона:
Код
В файле Single.h

// класс в виде синглетона
class Single
{
public:

    // функция, с помощью которой осуществляется ВЕСЬ доступ
    // к методам и данным класса.
    // Пример синтаксиса вызова: Single::instance()->some_function();
    static Single* instance();

    // Интерфейс класса

    void some_function();


private:
    
    // закрытые члены и методы.


    // объявление данных функций закрытыми предотвращает создание
    // более чем одного экземпляра класса.
    Single(int param);
    ~Single();
    // функции ниже не должны реализовываться
    Single(const Single&); // чтобы нельзя было передавать как параметр функции.
    Single& operator=(const Single&); // для запрета присваивания одного объекта другому
};


В файле реализации Single.c

//------------------------------------------------------------------------------
// Создание и предоставление доступа к единственному объекту
// класса без использования динамической памяти
//------------------------------------------------------------------------------
Single* Single::instance()
{
    static Single obj(some_param); // благодаря static объект создается единственный
                                                  // раз при первом обращении к instance()
    return &Single;
}

//------------------------------------------------------------------------------
// Реализация остальных методов класса
//------------------------------------------------------------------------------


Пример использования.

int main()
{
    // вызов метода класса
    Single::instance()->some_function();

    // или так
    Single *inst = Single::instance();

    inst->some_function();
}
jorikdima
Тема была создана месяц назад, а кучу полезных советов получил сейчас smile.gifsmile.gifsmile.gif Спасибо. Вот про синглетон то я и хотел услышать. Помню, что рассказывали нам про эти "идеологии", но забыл что именно. Спасибо.
AndrewKirs
Синглетон - красивая идея. Хотя все 3 варианта, предложенных здесь, работать будут. И конечное решение - за архитектором системы, в зависимости от его личных предпочтений и вкусов.
AndrewKirs
Еще раз подумал, и понял, что мне не нравится в статических переменных. Писал недавно большой проект, по форме это была статически линкуемая библиотека, работающая с определенными ресурсами. В какой-то момент ее неожиданно решили использовать в составе другой программы, многопоточной, которая и вызывала мою библиотеку в составе нескольких потоков. Пришлось срочно дописывать кусок, "развязывающий" и синхронизирующий доступ к статическим переменным. Так что синглетоны синглетонами, а все-таки у той идеи с управляющим классом есть свой собственный смысл - в такой библиотеке как у меня все бы работало без всяких дописываний.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.