Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 09:20
Оценка:
Подскажите решение, новичок я в С++

Ситуация, есть класс Image библиотеки GDI+. В своем классе я хочу объявить public переменную — объект класса Image. Но сделать я это не могу т.к. конструктор Image который без параметров у класса Image спрятан в protected.
Я пытаюсь
class MyClass {
public:
Gdiplus::Image srcImage; // Ошибка C2248: 'Gdiplus::Image::Image' : cannot access protected member declared in class 'Gdiplus::Image'
}

Определить объект класса можно только используя Image.Image(<имя файла>, 0) constructor, но сделать это при объявлении класса я не могу т.к. путь к файлу, естественно, я определяю потом по ходу работы приложения, в зависимости от действия пользователя. В общем цель, определить один раз объект Image и дальше использовать его уже откуда угодно в этом и других моих классах.
Не люблю умников, люблю умных.
Отредактировано 21.11.2014 9:22 Craftsman2004 . Предыдущая версия .
Re: Как объявить атрибутом класса объект другого класса?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 21.11.14 09:27
Оценка:
Здравствуйте, Craftsman2004, Вы писали:

C>Определить объект класса можно только используя Image.Image(<имя файла>, 0) constructor, но сделать это при объявлении класса я не могу т.к. путь к файлу, естественно, я определяю потом по ходу работы приложения, в зависимости от действия пользователя. В общем цель, определить один раз объект Image и дальше использовать его уже откуда угодно в этом и других моих классах.

Нужно создавать MyClass там, где ты знаешь имя файла которое нужно для конструирования Image, либо делать get/set Image методы в классе, но это самое лучшее решение.
Sic luceat lux!
Re[2]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 09:38
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, Craftsman2004, Вы писали:


C>>Определить объект класса можно только используя Image.Image(<имя файла>, 0) constructor, но сделать это при объявлении класса я не могу т.к. путь к файлу, естественно, я определяю потом по ходу работы приложения, в зависимости от действия пользователя. В общем цель, определить один раз объект Image и дальше использовать его уже откуда угодно в этом и других моих классах.

K>Нужно создавать MyClass там, где ты знаешь имя файла которое нужно для конструирования Image, либо делать get/set Image методы в классе, но это самое лучшее решение.

Если определить где я знаю имя файла — это значит определить имя файла как константу, и пользователь не сможет ее менять, что не подходит, либо я не так понял ответ. Класс Image это класс библиотеки, в которой я не могу ничего делать (Windows GDI+).
Не люблю умников, люблю умных.
Re: Как объявить атрибутом класса объект другого класса?
От: SI_16  
Дата: 21.11.14 09:38
Оценка: 2 (1) +4
объяви указатель
Gdiplus::Image *srcImage;
Re[2]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 09:46
Оценка:
Здравствуйте, SI_16, Вы писали:


SI_>объяви указатель

SI_>
SI_>Gdiplus::Image *srcImage;
SI_>

Сработало! Теперь бы осознать почему... Можешь в двух словах пояснить или ссылку дать?
Не люблю умников, люблю умных.
Re[3]: Как объявить атрибутом класса объект другого класса?
От: saf_e  
Дата: 21.11.14 09:50
Оценка: +1 :)
Здравствуйте, Craftsman2004, Вы писали:

C>Здравствуйте, SI_16, Вы писали:



SI_>>объяви указатель

SI_>>
SI_>>Gdiplus::Image *srcImage;
SI_>>

C>Сработало! Теперь бы осознать почему... Можешь в двух словах пояснить или ссылку дать?

Начните наверное отсюда: что читать
Re: Как объявить атрибутом класса объект другого класса?
От: Molchalnik  
Дата: 21.11.14 10:24
Оценка:
Здравствуйте, Craftsman2004, Вы писали:

class MyClass {
public:
Gdiplus::Image srcImage; // Ошибка C2248: 'Gdiplus::Image::Image' : cannot access protected member declared in class 'Gdiplus::Image'
}

Никак, т.к. его конструктор по умолчанию отмечен как "protected"
разве что добавить его инициализацию, например

Class MyClass {
public:
MyClass() : srcImage(параметры) {}
Gdiplus::Image srcImage; 
};

Но это сработает только если конструктор srcImage(параметры) существует и публичен

Оба примера, скомпиленные и проверенные:

class X {
 public:
  class Alpha {
   public:
    Alpha(int i) {}
   protected:
    Alpha() {}
  };
};

class Beta : public X::Alpha {
 public:
  //using X::Alpha::Alpha; //C++ вариант
  Beta()  :  X::Alpha::Alpha() {}
};

class MyClass {
 public:
  MyClass()  :    src_image_( (int)1 ) {}
  X::Alpha src_image_; 
};


class MyClass_2nd_variant {
 public:
  Beta src_image_; 
};


P.S. вложенность классов тут вообще ни при чём.
Re[3]: Как объявить атрибутом класса объект другого класса?
От: Molchalnik  
Дата: 21.11.14 10:30
Оценка:
Здравствуйте, Craftsman2004, Вы писали:

C>Сработало! Теперь бы осознать почему... Можешь в двух словах пояснить или ссылку дать?


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

Зато потом ты можешь проинициализировать его, например, с помощью
srcImage = new Gdiplus::Image(параметры);


Тогда new создаст нужный объект, а переменная srcImage будет хранить его адрес.


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


А вообще, Прочитай Уже Этот Грёбанный Мануал.

RTFM!!!!
Re[2]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 12:06
Оценка: :)
Здравствуйте, SI_16, Вы писали:


SI_>объяви указатель

SI_>
SI_>Gdiplus::Image *srcImage;
SI_>


Как я уже писал, так сработало! Спасибо!
Далее есть какой вопрос в продолжение темы:

В классе MyClass я по ходу программы инициализировал объект srcImage в функции класса:
void MyClass::LoadImageFromFile(CString & sPath)
{
    srcImage = &Gdiplus::Image(sPath,0);
}


Дернул функцию LoadImageFromFile по событию "типа открытия файла":
BOOL MyClass::OnNewDocument()
{
    CString sPath = _T("C:\\wb.jpg");
    LoadImageFromFile(sPath);
    return TRUE;
}

Все ок, типа документ с таким файлом теперь есть.

Дальше я в другом классе (Класс представления, используется Document/View архитектура) в другой функции создаю объект pMyClass:
void CWВСView::OnDraw(CDC* pDC)
{
MyClass * pMyClass;

    HDC hdc = *pDC;
    Graphics graphics(hdc);
    graphics.DrawImage(pMyClass->srcImage, 0, 0); //pMyClass ->srcImage пустой, не содержит файла.
}

pMyClass ->srcImage пустой, не содержит файла, т.к. создался новый объект класса pMyClass. Пробовал объявить srcImage как static – не прокатывает (ошибка при компиляции). Цель сделать чтение файла один раз, а не каждый раз когда содается новый объект класса MyClass.
Не люблю умников, люблю умных.
Отредактировано 21.11.2014 12:09 Craftsman2004 . Предыдущая версия . Еще …
Отредактировано 21.11.2014 12:09 Craftsman2004 . Предыдущая версия .
Re[3]: Как объявить атрибутом класса объект другого класса?
От: icWasya  
Дата: 21.11.14 12:32
Оценка:
Здравствуйте, Craftsman2004, Вы писали:

C>Здравствуйте, SI_16, Вы писали:



SI_>>объяви указатель

SI_>>
SI_>>Gdiplus::Image *srcImage;
SI_>>


C>Как я уже писал, так сработало! Спасибо!

C>Далее есть какой вопрос в продолжение темы:

C>В классе MyClass я по ходу программы инициализировал объект srcImage в функции класса:

C>
C>void MyClass::LoadImageFromFile(CString & sPath)
C>{
C>    srcImage = &Gdiplus::Image(sPath,0);
C>}
C>


C>Дернул функцию LoadImageFromFile по событию "типа открытия файла":

C>
C>BOOL MyClass::OnNewDocument()
C>{
C>    CString sPath = _T("C:\\wb.jpg");
C>    LoadImageFromFile(sPath);
C>    return TRUE;
C>}
C>

C>Все ок, типа документ с таким файлом теперь есть.

C>Дальше я в другом классе (Класс представления, используется Document/View архитектура) в другой функции создаю объект pMyClass:

C>
C>void CWВСView::OnDraw(CDC* pDC)
C>{
C>MyClass * pMyClass;

C>    HDC hdc = *pDC;
C>    Graphics graphics(hdc);
C>    graphics.DrawImage(pMyClass->srcImage, 0, 0); //pMyClass ->srcImage пустой, не содержит файла.
C>}
C>

C>pMyClass ->srcImage пустой, не содержит файла, т.к. создался новый объект класса pMyClass. Пробовал объявить srcImage как static – не прокатывает (ошибка при компиляции). Цель сделать чтение файла один раз, а не каждый раз когда содается новый объект класса MyClass.

void MyClass::LoadImageFromFile(CString & sPath)
{
  if(srcImage)
     delete srcImage;
  srcImage = new Gdiplus::Image(sPath,0);
}


и не забыть в конструкторе MyClass проинициализировать srcImage нулём:
Re[4]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 12:47
Оценка:
W>
W>void MyClass::LoadImageFromFile(CString & sPath)
W>{
W>  if(srcImage)
W>     delete srcImage;
W>  srcImage = new Gdiplus::Image(sPath,0);
W>}
W>


W>и не забыть в конструкторе MyClass проинициализировать srcImage нулём:


Так получаю ошибку:

IntelliSense: no instance of overloaded "Gdiplus::Image::operator new" matches the argument list
argument types are: (unsigned int, const char [101], int)


На строчку
W> if(srcImage)
W> delete srcImage;
получаю в рантайме:

Unhandled exception at 0x013F801D in prog.exe: 0xC0000005: Access violation reading location 0xCDCDCDCD.

Не люблю умников, люблю умных.
Отредактировано 21.11.2014 12:56 Craftsman2004 . Предыдущая версия . Еще …
Отредактировано 21.11.2014 12:55 Craftsman2004 . Предыдущая версия .
Re[3]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 21.11.14 14:24
Оценка:
Вопрос решен. Спасибо всем кто отвечал.

Сначала объявил переменную как static:
class MyClass {
public:
    statiс Gdiplus::Image *srcImage;
}

потом добавил ее определение таким образом (в описании реализации класса):
Gdiplus::Image *MyClass::srcImage = nullptr;
Не люблю умников, люблю умных.
Re[3]: Как объявить атрибутом класса объект другого класса?
От: enji  
Дата: 21.11.14 15:51
Оценка: +1
Здравствуйте, Craftsman2004, Вы писали:

C>
C>    srcImage = &Gdiplus::Image(sPath,0);
C>


Не надо так делать. Ты все таки почитай мануал
Re[4]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 22.11.14 18:34
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, Craftsman2004, Вы писали:


C>>
C>>    srcImage = &Gdiplus::Image(sPath,0);
C>>


E>Не надо так делать. Ты все таки почитай мануал


Другого варианта я не знаю, как я писал new не работает в данном случае. Если есть вариант, подскажи, пожалуйста.
Не люблю умников, люблю умных.
Re[5]: Как объявить атрибутом класса объект другого класса?
От: BulatZiganshin  
Дата: 22.11.14 18:38
Оценка: :))
Здравствуйте, Craftsman2004, Вы писали:

C>На строчку

W>> if(srcImage)
W>> delete srcImage;
C>получаю в рантайме:

попробуй поменять эти строчки местами, попробуй записать их задом наперёд. словом, отнесись к своей професси творчески — это же не математика где надо читать скучные учебники!
Люди, я люблю вас! Будьте бдительны!!!
Отредактировано 22.11.2014 20:17 BulatZiganshin . Предыдущая версия .
Re[4]: Как объявить атрибутом класса объект другого класса?
От: Ops Россия  
Дата: 22.11.14 19:13
Оценка:
Здравствуйте, icWasya, Вы писали:

W>
W>  if(srcImage)
W>     delete srcImage;
W>


Не нужно проверки
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[5]: Как объявить атрибутом класса объект другого класса?
От: enji  
Дата: 23.11.14 05:16
Оценка: +2
Здравствуйте, Craftsman2004, Вы писали:


C>>>
C>>>    srcImage = &Gdiplus::Image(sPath,0);
C>>>


E>>Не надо так делать. Ты все таки почитай мануал


C>Другого варианта я не знаю, как я писал new не работает в данном случае. Если есть вариант, подскажи, пожалуйста.


ты понимаешь, что тут происходит? Ты создаешь временный объект (который живет до конца выражения) на стеке и берешь его адрес. После перехода к следующей строчке объекта уже нет, вызвался его деструктор. И у тебя указатель на область памяти, в которой когда-то был объект. Дальше эта область памяти будет перезаписана новыми данными. Попытка позвать методы этого объекта или вызвать delete srcImage вероятно приведет к расстрелу памяти или срабатыванию аппаратной защиты. А может быть видимых проявлений не будет, зато если потом в другом месте поменять одну строчку — программа упадет.

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

ЗЫ С чего ты взял, что new не работает? Он чудесно работает. Напиши минимальный пример, запости сюда, если он работать не будет.
ЗЫЫ Лучше использовать не голые указатели, а unique_ptr, если есть такая возможность
ЗЫЫЫ А еще лучше выбрать время и почитать книжку
Re[6]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 24.11.14 15:07
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, Craftsman2004, Вы писали:



C>>>>
C>>>>    srcImage = &Gdiplus::Image(sPath,0);
C>>>>


E>>>Не надо так делать. Ты все таки почитай мануал


C>>Другого варианта я не знаю, как я писал new не работает в данном случае. Если есть вариант, подскажи, пожалуйста.


E>ты понимаешь, что тут происходит? Ты создаешь временный объект (который живет до конца выражения) на стеке и берешь его адрес. После перехода к следующей строчке объекта уже нет, вызвался его деструктор. И у тебя указатель на область памяти, в которой когда-то был объект. Дальше эта область памяти будет перезаписана новыми данными. Попытка позвать методы этого объекта или вызвать delete srcImage вероятно приведет к расстрелу памяти или срабатыванию аппаратной защиты. А может быть видимых проявлений не будет, зато если потом в другом месте поменять одну строчку — программа упадет.


E>Ну т.е. это все основы, которые стоит почитать в любой книжке по плюсам, а не выяснять методом проб и ошибок.


E>ЗЫ С чего ты взял, что new не работает? Он чудесно работает. Напиши минимальный пример, запости сюда, если он работать не будет.

E>ЗЫЫ Лучше использовать не голые указатели, а unique_ptr, если есть такая возможность
E>ЗЫЫЫ А еще лучше выбрать время и почитать книжку

Спасибо!
C этим разобрался, на минимальном примере тоже все изучил, все работает как надо, но:
Пробую использовать опратор new с классом из GDI+:
Gdiplus::Bitmap *srcImage;
srcImage = new Gdiplus::Bitmap(sPath,0); //получаю ошибку: no instance of overloaded "Gdiplus::Bitmap::operator new" matches the argument list, argument types are: (unsigned int, const char [101], int). Но таких аргументов ни в одном конструкторе класса Bitmap нет. Конструктора без параметров тоже нет.


srcImage = Gdiplus::Bitmap::FromFile(sPath,0); //так работает, т.к. FromFile возвращает указатель на объект. Но мне хотелось бы создать объект в heap, т.к. большой он может быть.
Не люблю умников, люблю умных.
Отредактировано 24.11.2014 15:14 Craftsman2004 . Предыдущая версия . Еще …
Отредактировано 24.11.2014 15:13 Craftsman2004 . Предыдущая версия .
Отредактировано 24.11.2014 15:12 Craftsman2004 . Предыдущая версия .
Re[7]: Как объявить атрибутом класса объект другого класса?
От: DarkEld3r  
Дата: 24.11.14 16:11
Оценка:
Здравствуйте, Craftsman2004, Вы писали:

srcImage = Gdiplus::Bitmap::FromFile(sPath,0); //так работает, т.к. FromFile возвращает указатель на объект. Но мне хотелось бы создать объект в heap, т.к. большой он может быть.

Дык, Bitmap::FromFile как раз и возвращает указатель на обьект в хипе, разве нет?
Re[8]: Как объявить атрибутом класса объект другого класса?
От: Craftsman2004  
Дата: 24.11.14 16:44
Оценка:
Здравствуйте, DarkEld3r, Вы писали:

DE>Здравствуйте, Craftsman2004, Вы писали:


DE>
DE>srcImage = Gdiplus::Bitmap::FromFile(sPath,0); //так работает, т.к. FromFile возвращает указатель на объект. Но мне хотелось бы создать объект в heap, т.к. большой он может быть. 
DE>

DE>Дык, Bitmap::FromFile как раз и возвращает указатель на обьект в хипе, разве нет?

Может быть, но подтверждение этому я не нашел на msdn. Если так, интересно он сам потом сделает delete?
Не люблю умников, люблю умных.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.