Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как запретить создание экземпляра класса?


Автор: akahan 1.3.2007, 16:09
Привет, хакеры!
Мне нужно при создании экземпляра класса запретить его создание! Т.Е., допустим:
Код

class foo
{
   foo(int b)
  {
      if(!b)
         delete this;
      else
         c=b;
  }

private:
   int c;
};



Правильный ли это код??? Если нет, то как мне сделать, что-бы при не прохождениии условия экземпляр класса не создавался, а возвращался допустим NULL.

Автор: Fazil6 1.3.2007, 16:18
Код

Мне нужно при создании экземпляра класса запретить его создание!

тут нужно бросать исключение по проверке условия

а лучше вот так
Код

class foo
{
public:
static foo * Create(int b)
{
 if(!b) return NULL;
 return new foo(b);
}
private:
   foo(int b) : c(b)
  {
             
  }

private:
   int c;
};

// создавать так

foo * f(foo::Create(b)) ; // не забыть удалить потом



Код

// еще лучше использовать не указатель, а
typedef boost::shared_ptr<foo> too_t;

class foo
{
public:
static too_t Create(int b)
   {
      if(!b) return NULL;
      return new foo(b);
   }
private:
   foo(int b) : c(b)
  {
             
  }

private:
   int c;
};

// создавать так

too_t  f(foo::Create(b)) ; // удалится когда надо само




Автор: skyboy 1.3.2007, 16:31
вариант попроще(как это реализовано в паттерне "Одиночка"): делаешь конструктор private, а вместо new foo используешь вызов некой функции getInstance. правда, я не знаю, можно ли объявить статический метод, тип результата которого - сам класс... или, может, потом(при создании) приведение типов делать надо будет... Не  в курсе smile

Автор: Fazil6 1.3.2007, 16:36
Цитата

вариант попроще(как это реализовано в паттерне "Одиночка"): делаешь конструктор private, а вместо new foo используешь вызов некой функции getInstance. правда, я не знаю, можно ли объявить статический метод, тип результата которого - сам класс... или, может, потом(при создании) приведение типов делать надо будет... Не  в курсе

Чем же он проще? Я именно это и написал. 

Автор: skyboy 1.3.2007, 16:36
опоздал smile

Добавлено @ 16:37 
Цитата(Fazil6 @  1.3.2007,  15:36 Найти цитируемый пост)
Чем же он проще? Я именно это и написал.  

когда я писал свой пост, ты ешё его не редактировал. неужто сложно догадаться, что пять минут - совсем небольшой срок? smile

Автор: akahan 2.3.2007, 01:29
Допустим, последний вариант хороший, но как быть если foo наследуется от bar?
Что должна создавать Create класс foo или bar?
По идее расшаренная функция Create  должна быть в классе bar. Можно ли будет переопределять эту функцию в наследуемых классах? Или что делать в таком случае? Можно, конечно и непереопределять, но тогда придется делать каждый раз dynamic_cast?

Автор: Fazil6 2.3.2007, 01:57
Цитата

По идее расшаренная функция Create  должна быть в классе bar. Можно ли будет переопределять эту функцию в наследуемых классах? Или что делать в таком случае? Можно, конечно и непереопределять, но тогда придется делать каждый раз dynamic_cast?

тут лучше фабрику юзать.

Код


// хедер 
class FooBase  // класс абстрактный
{
public:
// тут определяется интерфейс 
// пустыми виртуальными функциями

};

typedef boost::shared_ptr<FooBase> Foo_t;

// функция возвращает реально созданный объект-наследника FooBase в зависимости от name
Foo_t FooFactory(const std::string &name); 

// можно сделать подругому, когда для каждого наследника есть отдельная функция 
Foo_t GetFooA();
Foo_t GetFooB();
Foo_t GetFooC();   

// объфвление и реализация самих наследников в cpp, при этом бесконтрольное создание их экземпляров теоретически невозможно, 
// ибо о них снаружи вообще никто не знает и они реализуют интерфейс базового класса

//  фабричные функции контролируют создание конкретных объектов


Автор: console 2.3.2007, 23:12
Ммм... а может стоит поместить чистую виртуальную функцию в класс, чтобы сделать его абстрактным?

Автор: Athlon 2.3.2007, 23:29
Цитата(console @  2.3.2007,  23:12 Найти цитируемый пост)
а может стоит поместить чистую виртуальную функцию в класс

+1, тогда уж точно создать экземпляр класса не удастся  smile 

Автор: Fazil6 2.3.2007, 23:53

Цитата(console @  2.3.2007,  22:12 Найти цитируемый пост)
Ммм... а может стоит поместить чистую виртуальную функцию в класс, чтобы сделать его абстрактным?


интересная мысль... А может не надо?

Автор: Xenon 3.3.2007, 00:02
console, тогда тому, кто будет читать твой код, будет непонятно, чего хочешь сделать

Автор: console 3.3.2007, 00:23
Цитата(Xenon @  2.3.2007,  23:02 Найти цитируемый пост)
console, тогда тому, кто будет читать твой код, будет непонятно, чего хочешь сделать


Почему непонятно... Это ж классика..........
 Раз класс содержит хоть одну чистую виртуальную функцию - значит он абстрактный...... Правила эстетики

Автор: Daevaorn 3.3.2007, 00:35
Цитата(console @  3.3.2007,  01:23 Найти цитируемый пост)
Почему непонятно... Это ж классика..........
 Раз класс содержит хоть одну чистую виртуальную функцию - значит он абстрактный...... Правила эстетики 

судя по вопросу автора данной темы, вариант с фабрикой его устроит. А абстрактный класс это уже другая песьня.

Автор: Xenon 3.3.2007, 02:14
console, ну я буду думать, что твой не только нельзя создать, но он еще и наследуется где-то, хотя это на самом деле не так smile

Автор: threef 3.3.2007, 11:15
Код

class A{
public:
static A& create(void* param=NULL)
{
  if(!param) throw "create error";
  static  A x(param);
  return x;
}
~A(){}
protected :
   A(void* param)
{
 ...tarambaram
}
};
main()
{
   try{
        A& a=A::create();
   }
   catch(char*s)
   {
      cout<<s;
  }
}



и обьект не  динамический , и не создастся - в общем, я согласен с  Fazil6

Автор: Fazil6 3.3.2007, 16:36
threef, неправильный код.
Код

static A& create(void* param=NULL)
{
  if(!param) throw "create error";
  static  A x(param);
  return x;
}

как создать второй объект? третий? 

Код

throw "create error";

...


catch(char*s)

это конечно не ошибка, но это ведь плохо... Это исключение ради исключения. Выбор варианта обработки исключения должен производится на основании типа объекта исключения, а не его значения. Пока мы не проверим что в строке, мы не знаем что за ошибка. Я не придираюсь - просто глаз всегда цепляется за такие ляпы.


Автор: Любитель 4.3.2007, 00:52
Цитата(console @  2.3.2007,  23:12 Найти цитируемый пост)
а может стоит поместить чистую виртуальную функцию в класс, чтобы сделать его абстрактным?

Немного в тему: чтобы экземпляров класса точно не создали, лучше всего не писать сам класс. Другой вариант - в документации жирно и крупно написать - не создавай экземпляров этого класса.

Автор: console 4.3.2007, 01:00
Любитель
Цитата(Любитель @  3.3.2007,  23:52 Найти цитируемый пост)
чтобы экземпляров класса точно не создали, лучше всего не писать сам класс.

Не лучше... он может служить в качестве базового класса, с определенным набором методов и данных для наследников...

2й вариант более приемлим ИМХО

Автор: Rockie 4.3.2007, 02:05
Цитата(akahan @  1.3.2007,  16:09 Найти цитируемый пост)
Мне нужно при создании экземпляра класса запретить его создание


Цитата(akahan @  2.3.2007,  01:29 Найти цитируемый пост)
как быть если foo наследуется от bar?


сделать конструктор protected?


Автор: Fazil6 4.3.2007, 02:07
Цитата(Rockie @  4.3.2007,  01:05 Найти цитируемый пост)
сделать конструктор protected?

и что по твоему это даст?

Автор: Rockie 4.3.2007, 02:15
Fazil6, запрет создания объекта при возможности создать наследников, imho. То есть в явном виде сам объект базового не будет существовать. Этj размышления, не проверял. 


Автор: Rockie 4.3.2007, 02:34
Проверил.
Код

class A{
protected:
    A(){}
};

class B: public A{
public:
    B(){}
};

int main()
{
    //A a;    // cannot access protected member declared in A
    B b;      // а тут все хорошо
    return 0;
}


Таким образом мы разрешаем наследование, но запрещаем создание объекта базового класса.


Автор: Xenon 4.3.2007, 03:07
Ну по-моему и так понятно - private, если класс не наследуется, protectd, если наследуется. Явно указывать защищенность конструктора и деструктора надо, как завещал Саттер smile

Автор: Rockie 4.3.2007, 14:15
Цитата(Xenon @  4.3.2007,  03:07 Найти цитируемый пост)
Ну по-моему и так понятно - private, если класс не наследуется, protectd, если наследуется. Явно указывать защищенность конструктора и деструктора надо, как завещал Саттер  smile 

Саттер еще живой. Если он и указывал закрывать конструкторы, то явно не в том контексте в каком ты понял. 


Автор: Xenon 4.3.2007, 15:58
Rockie, я не говорю "закрывать", я говорю "указывать спецификатор доступа" (public,protected,private) - обязаловка

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)