Visual C++ Linkowanie zmiennych - extern

0

Witam, mam problem z linkowaniem zmiennych z okna głownego do okna podrzędnego:

1>oknotmp.obj : error LNK2020: unresolved token (0A00000D) "int oknotmp::liczby" (?liczby@oknotmp@@$$Q3HA)
1>okno2.obj : error LNK2020: unresolved token (0A000007) "int oknotmp::liczby" (?liczby@oknotmp@@$$Q3HA)
1>okno2.obj : error LNK2001: unresolved external symbol "int oknotmp::liczby" (?liczby@oknotmp@@$$Q3HA)
1>oknotmp.obj : error LNK2001: unresolved external symbol "int oknotmp::liczby" (?liczby@oknotmp@@$$Q3HA)
1>C:\Users\Adm\Documents\Visual Studio 2010\Projects\oknotmp\Debug\oknotmp.exe : fatal error LNK1120: 3 unresolved externals 

Kod pierwszego okna:

 
#pragma once
#include "okno2.h"
#include "stdafx.h"

int liczby=5;

namespace oknotmp {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Summary for Form1
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(51, 43);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(200, 78);
			this->button1->TabIndex = 0;
			this->button1->Text = L"button1";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 262);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->ResumeLayout(false);

		}
#pragma endregion
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			okno2^ OknoUzytkownika = gcnew okno2();
                 OknoUzytkownika->Show();
				
			 }
	};
}

Kod drugiego:

 
#pragma once
#include "stdafx.h"


namespace oknotmp {
	extern int  liczby;
	
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Summary for okno2
	/// </summary>
	public ref class okno2 : public System::Windows::Forms::Form
	{
	public:
		okno2(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~okno2()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(66, 49);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(138, 101);
			this->button1->TabIndex = 0;
			this->button1->Text = L"button1";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &okno2::button1_Click);
			// 
			// okno2
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 262);
			this->Controls->Add(this->button1);
			this->Name = L"okno2";
			this->Text = L"okno2";
			this->Load += gcnew System::EventHandler(this, &okno2::okno2_Load);
			this->ResumeLayout(false);

		}
#pragma endregion
	private: System::Void okno2_Load(System::Object^  sender, System::EventArgs^  e) {
			 }
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
				 MessageBox::Show(Convert::ToString(liczby));
			 }
	};
}

Szukałem na stronie microshitu, ale nic tam nie ma wyjasnionego, z reszta wujek google też niewiele wie na ten temat. Ktoś wie co go boli ?

0

Zmienna globalna liczby jest zdefiniowana poza przestrzenią nazw oknotmp, natomiast w drugim oknie deklarujesz zmienną globalną (extern) wewnątrz tej przestrzeni. Zdecyduj się, bo teraz linker traktuje deklarację z drugiego okna jako odwołanie do zmiennej w namespace, a że takiej nie ma, wywala błąd.

0

Zmienna liczby jest u ciebie w przestrzeni globalnej, a potem dajesz extern w przestrzeni oknotmp.
Poza tym powinna być w pliku .cpp, a w .h daj tylko jako extern bo inaczej dostaniesz wielokrotną definicję.

Krótko: zrób pole w klasie (może być statyczne), wywal globalną.

0

Niestety, designer robi niezły burdel wrzucając cały kod do jednego pliku .h, co się mści gdy robimy #include jednej formy w drugiej.

Tak naprawdę można cały plik Form1.h przerobić tak, by wszystkie ciała metod przenieść do Form1.cpp, tak jak to w C++ się normalnie robi:

#pragma once
#include "stdafx.h"
#include "okno2.h"

namespace oknotmp {
        extern int liczby;
 
        using namespace System;
        using namespace System::ComponentModel;
        using namespace System::Collections;
        using namespace System::Windows::Forms;
        using namespace System::Data;
        using namespace System::Drawing;
 
        public ref class Form1 : public System::Windows::Forms::Form
        {
        // standardowe śmieci
        public:
                Form1(void);
        protected:
                ~Form1();
        private:
                System::ComponentModel::Container ^components;
                void InitializeComponent(void);

        // komponenty
        private:
                System::Windows::Forms::Button^  button1;
        
        // zdarzenia
        private:
                void button1_Click(System::Object^  sender, System::EventArgs^  e);
        };
}

Zawartość Form1.cpp myślę że łatwo sobie wyobrazić, jak ktoś zna C++.

#include "stdafx.h"
#include "Form1.h"

namespace oknotmp {

int liczby = 5;

Form1::Form1(void)
{
        InitializeComponent();
}

#pragma region Windows Form Designer generated code
void Form1::InitializeComponent(void)
{
        // CIACH
}
#pragma endregion

// itd.

To (oczywiście) się skompiluje, ale co ważniejsze - designer się wcale nie wywala na tak przerobionym pliku! Jednak każdą nową metodę (zdarzenie) usilnie będzie wrzucał do .h zamiast .cpp, i trzeba ręcznie przenosić definicję do .cpp zostawiając w .h tylko deklarację.

Za to mamy porządek w kodzie (w typowym stylu C++) i zero problemów z #include i externami.

1 użytkowników online, w tym zalogowanych: 0, gości: 1