2016-01-11 12 views
-1

Недавно я вернулся на C++ с языков сценариев, таких как PHP и LSL, и некоторые из его правил определения области меня смущают.Как понять правила C++ для определения переменных?

Скажет, у меня есть Viewer.h вроде так:

class Viewer { 

    public: 

     Viewer(); 
     ~Viewer(); 

     void ping(); 
     void setBgColour(int r, int g, int b, int a); 

     float bg_r; 
     float bg_g; 
     float bg_b; 
     float bg_a; 
}; 

и Viewer.C вроде так:.

#include "Globals.h" 
#include "Viewer.h" 

Viewer::Viewer() {} 
Viewer::~Viewer() {} 

void Viewer::ping() { 

    cout << "Viewer::ping() " << endl; 
} 

void Viewer::setBgColour(int r, int g, int b, int a) { 

    bg_r = r/255.0; 
    bg_g = g/255.0; 
    bg_b = b/255.0; 
    bg_a = a/255.0; 
} 

Я объявленный экземпляр моего просмотра класса в Global { h | C} как «extern», чтобы иметь возможность доступа к экземпляру глобального зрителя из других файлов.

Теперь рассмотрим это, когда я называю глобальные методы экземпляра для просмотра, например, в UI.C:

viewer->ping(); 
viewer->setBgColour(123, 45, 56, 255); 

viewer-> пинг() работает нормально, но viewer-> setBgColour() дает мне при попытке доступа к переменным экземпляра bg_r, bg_g, bg_b и bg_a.

Насколько я понимаю, я не имею доступа к правильному экземпляру зрителя.

viewer-> ping() не имеет значения, поскольку он будет просто эхо-текст в cout независимо от экземпляра, из которого он действительно вызван. Но setBgColour() нуждается в доступе к правильным местам памяти, поэтому он не работает, когда он не может их найти.

Это смущает меня, поскольку я был/находится под впечатлением, что объявление моего экземпляра зрителя как «extern» будет «просто работать». Дурак я. Я пробовал объявлять переменные как «статические», но это меня просто смутило.

+3

Вы действительно выделили 'Viewer', или у вас есть неинициализированный указатель? Если все, что у вас есть, это «Viewer * viewer», то у вас есть последнее. –

+1

Вы должны показать строку кода, в которой вы создаете зрителя! Я подозреваю, что @JonathanPotter прав. –

+0

Является ли значение 'viewer' равным' nullptr'? Если 'viewer' является глобальным, тогда вы должны проверить, что он был создан до его использования. –

ответ

1

Если у вас уже не сделано до viewer в коде перед опубликованными строками, то у вас есть неинициализированный указатель Viewer* viewer. Разделение такого указателя вызывает ошибку сегментации. Если вы хотите исправить это, вы должны назначить адрес созданного объекта указателю.

Возможно:

(в начале main)

viewer = new Viewer(); 

// some code here 

delete viewer; 

Или назначить адрес существующей глобальной переменной к ней.

0

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

например.

#include <iostream> 
using std::cout; 

class Viewer 
{ 
    float bg_r; 
    float bg_g; 
    float bg_b; 
    float bg_a; 

    Viewer(Viewer const&) = delete; 
    Viewer& operator=(Viewer const&) = delete; 

    public: 

    Viewer() 
     : bg_r(0.0), bg_g(0.0), bg_b(0.0), bg_a(0.0) 
    {} 
    void ping(); 
    void setBgColour(int r, int g, int b, int a);  
}; 

void Viewer::ping() 
{ 
    cout << "Viewer::ping()\n"; 
} 

void Viewer::setBgColour(int r, int g, int b, int a) 
{ 
    bg_r = r/255.0; 
    bg_g = g/255.0; 
    bg_b = b/255.0; 
    bg_a = a/255.0; 
} 

Viewer& GetViewer() 
{ 
    static Viewer v; 
    return v; 
} 

int main() 
{ 
    GetViewer().ping(); 
    GetViewer().setBgColour(1,2,3,4); 
} 
+1

Синглтон - неплохая идея, но эта реализация по-прежнему позволяет создать другой экземпляр, подобный этому: 'Viewer im_a_copy = Viewer :: GetViewer();'. Исправление состоит в том, чтобы удалить конструктор копирования или пометить его как закрытый. – Ben

+0

Хорошая точка зафиксирована. спасибо –

+0

Спасибо, Пол, за этот комментарий.Я обсуждал, что с помощью синглтонов это путь, но затем все обмануты дебатами «одиночные игры - злые» и вместо этого используются глобальные. Ваш комментарий и фрагмент кода также заставили меня вернуться и вернуться к идеям выделения стека и кучи и памяти в C/C++ в целом - так что для его метаэффекта я хотел бы выбрать ваш ответ в качестве предпочтительного для моего вопроса , – userwithname