Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Помогите с функцией


Автор: Riddik 1.6.2009, 15:13
Приветsmile

Подскажите, как правильно написасть функцию:

есть абстрактный базовый класс Base и несколько производных от него,
eсть контейнер vector, содержащий указатели на базовый класс.

Код

std::vector<Base*> pb;


Функция нужна такая:
Код

void add(/*не знаю что*/ obj) {pb.push_back(new obj);}


Где obj - наследник базового класса Base.


Автор: mrbrooks 1.6.2009, 15:22
Riddik, а почему бы сразу не записывать в вектор производный класс? можно без указателя.

Автор: Riddik 1.6.2009, 15:26
Нужно через функцию, потому что pb - это private - член другого класса.

Добавлено через 1 минуту и 48 секунд
И потому что в векторе будут разные производные классы

Автор: REZiaMIX 1.6.2009, 15:54
Код

void add(Base* obj) 
{
       pb.push_back(obj);
}

Так ?

Автор: Riddik 1.6.2009, 16:49
REZiaMIX,  неа. Объект нужно создать, его не существует. нужно создать объект и поместить в вектор его адрес : push_back(new obj);

Автор: zim22 1.6.2009, 17:32
Riddik, что-то типа такого?
Код

class Base {
public:
  virtual ~Base() = 0;
};
Base::~Base() { }

class Derived1 : public Base {
public:
  Derived1(std::string n) :name(n) {  }
  ~Derived1() {}
private:
  std::string name;
};

class Derived2 : public Base {
public:
  ~Derived2() {}
};

template <typename T>
void add(std::vector<Base*> &vt, T &obj) {
  vt.push_back(new T(obj));
}
int _tmain(int argc, _TCHAR* argv[])
{
  std::vector<Base*> pb;
  add(pb, Derived1("parameters"));
  add(pb, Derived2());

    return 0;
}

Автор: Riddik 1.6.2009, 19:53
zim22, спасибо smile.

Шаблонная функция мне и нужнаsmile 

Автор: Riddik 1.6.2009, 22:02
Только я не очень понял, почему так работает:

add(derived());

а так нет:

add(derived);

просто нет скобок после имени класса.

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

Если можно, объясните.

Автор: Riddik 1.6.2009, 22:27
Ещё проблема. Объект создаётся дважды. При вызове функции создаётся объект, затем его копия передаётся в вектор - т.е. создаётся объект ещё раз.

Как этого избежать?

передача по ссылке ничего не меняет. 

Не знаю, какой делать конструктор копии, чтобы объект не создавался два раза.

Мне нужно, чтобы аргумент функции лишь говорил, какой класс положить в вектор.

Добавлено через 11 минут и 31 секунду
Вот код:
Код

template<class T> void add(T) {pb.push_back(new T);}


При вызове функции add(der());

вызывается конструктор der();
вызывается конструктор der();
вызывается деструктор ~der();

И после очистки вектора 

вызывается деструктор ~der();

Можно как-нибудь сделать, чтобы объект создавался только когда его адрес помещается в контейнер, один раз?

Автор: Rififi 2.6.2009, 00:42
Riddik, 
читать про паттерны Factory, Builder, Virtual Constructor, Prototype

Автор: zim22 2.6.2009, 07:51
Цитата(Riddik @  1.6.2009,  22:02 Найти цитируемый пост)
 почему так работает:add(derived());а так нет:add(derived);

потому что в случае с круглыми скобками мы конструируем объект. и его тип уже вычисляется при передаче в функцию add
это аналогично следующей форме записи:
Код

add(pb, Derived2::Derived2());

без круглых скобок - не работает, т.к. форма записи не допустимая. smile

Rififi дело говорит. почитайте про паттерны.  smile 

Автор: Riddik 2.6.2009, 08:39
Спасибо за помощьsmile

Автор: mes 2.6.2009, 09:40
Цитата(Riddik @  1.6.2009,  21:27 Найти цитируемый пост)

Можно как-нибудь сделать, чтобы объект создавался только когда его адрес помещается в контейнер, один раз? 

Вы хотите чтоб создавался объект   по типу который Вы передаете   или    как копия объекта.
Если первое, то 
Код

template<class T> void add() {pb.push_back(new T());}
//
...add<Derived>();

Для второго случая  преимущество в том, что можно использовать любой необходимый конструктор (а потом просто снимется копия).

Но ваша конструкция мне внушает опасения, мне кажется Вы идете неправильным путем. Если не секрет зачем Вам такое понадобилось ?
Зачем нужно клонировать объект ?

Автор: Riddik 2.6.2009, 11:31
mes, мне нужно это: "создавался объект   по типу который Вы передаете"


Как раз копия мне не нужна!

Спасибо! Вы очень помогли! 

Автор: Riddik 2.6.2009, 12:09
Ругается на 
Код

add<Derived>();


Пишет 'Derived' : illegal use of this type as en expression, не пойму почему. 

Автор: azesmcar 2.6.2009, 12:19
Riddik

Желательно было бы посмотреть на код. использование template<typename T> вместо template<class T> может помочь

Автор: Riddik 2.6.2009, 12:29
azesmcar, 

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

Код

class Big 
{
std::vector<base*> pb;
public:
template<class T> void add() {pb.push_back(new T);}
};

class der : public base
{
public:
der();
~der();
};

Big Just;
Just.add<der>();


Автор: zim22 2.6.2009, 12:41
Цитата(Riddik @  2.6.2009,  12:29 Найти цитируемый пост)
 Что-то я не так сделал

Код

#include <vector>

class base {
public:
  virtual ~base() = 0 { }
};
class Big {
  std::vector<base*> pb;
public:  
  template<class T> 
  void add() {pb.push_back(new T);}
};

class der : public base
{
public:
  der(){}
  ~der(){}
};


int _tmain(int argc, _TCHAR* argv[])
{
  Big just;
  just.add<der>();

    return 0;
}

Автор: Riddik 2.6.2009, 13:09
zim22, у меня в точности так. smile 
разве только что вместо 
Код

 virtual ~base() = 0 { }



у меня 
Код

 virtual ~base() { }



Автор: zim22 2.6.2009, 13:10
Цитата(Riddik @  2.6.2009,  13:09 Найти цитируемый пост)
у меня в точности так

у меня работает. опять наверно из-за различных компиляторов проблема... 
***
чтобы в gcc работало, нужно определение деструктора вынести за класс
Код

class base {
public:
  virtual ~base() = 0;
};
base::~base() { }

Автор: mes 2.6.2009, 13:12
Цитата(Riddik @  2.6.2009,  12:09 Найти цитируемый пост)
zim22, у меня в точности так. smile 

т.е. вариант zim22 у Вас не работает ? тогда скажите какой компилятор Вы используйте.

Добавлено через 1 минуту и 32 секунды
и вообще не понимаю зачем мудрить можно же просто передавать готовый объект на хранение.
Вот пример показывающий оба способа. Я бы выбрал второй.
Код

#include <iostream>
#include <vector>

class Base
{
    public:
         virtual ~Base () {}
};
class Derived : public Base
{
    public:
        Derived () { std::cout << "created"<<std::endl; }
};

class Container
{
    public:
        template <class T> void add () { m_vec.push_back(new T()); } // 1.
        void add (Base *p)             { m_vec.push_back(p);       } // 2.


    private:
        std::vector<Base*> m_vec;

};

int main()
{
    Container c;

    c.add<Derived>();        // 1.
    c.add (new Derived());   // 2.

    system ("pause");
   return 0;
}

Автор: Riddik 2.6.2009, 13:18
Компилятор VC++ 6.0

Ваш второй способ, скорее всего, в моём случае подойдёт. Сейчас ещё прикину smile

Автор: zim22 2.6.2009, 13:23
Цитата(Riddik @  2.6.2009,  13:18 Найти цитируемый пост)
Компилятор VC++ 6.0

эээ, без комментариев. на нём ещё мой дедушка программировал smile

Автор: mes 2.6.2009, 13:27
Цитата(Riddik @  2.6.2009,  12:18 Найти цитируемый пост)
Компилятор VC++ 6.0

берите тогда второй способ и не ищите лишних проблем smile

Автор: Riddik 2.6.2009, 13:45
Есть и експресс 2008, но привычка...smile

Спасибо за всё!

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