Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++/CLI: uusien olioiden luonti loopissa

Tampio [15.04.2009 15:19:23]

#

Nyt on todennäköisesti simppeli kysymys ja mulla on vain syntaksi hukassa.
Haluaisin luoda luokasta olioita silmukassa, niin että olioiden nimet tulee indeksimuuttujan perusteella olio0, olio1, olio2 jne.
Olioita ei tule montaa, joten niiden esittely hoituisi käsipelilläkin, mutta myöhemmin täytyisi päästä käsiksi olioiden muuttujiin.
Virheellisellä syntaksilla luotu koodi varmaa valaisee paremmin mitä ajan takaa:

for (int i = 0; i <= 5; i++) {
omaluokka (olio+i); //luo oliot "olio0, olio1, ... olio4
}
void funktio(int k) {
//jos funktion parametri on esim. k=2, asetetaan olio2 muuttujan arvo
(olio+k).muuttuja = 66;
}

Zeeli [15.04.2009 15:41:10]

#

int num_oliot = 5;
omaluokka *oliot = new omaluokka[num_oliot]; //Varataan muistia taulukolle jonka koko on num_oliot

for(int i = 0; i < num_oliot; i++) {
    oliot[i]->muuttuja = 66; //Asetetaan indeksin i arvoksi 66
}

delete[] oliot;

eq [15.04.2009 15:50:08]

#

Tampio kirjoitti:

for (int i = 0; i <= 5; i++) {
omaluokka (olio+i); //luo oliot "olio0, olio1, ... olio4
}

Yo. silmukka loisi 6 oliota, eli nollasta viiteen.

Käytä vectoria.

#include <vector>
// - -
std::vector<omaluokka> oliot(5); // luodaan 5 oliota
oliot[n].toimi(); // käytä n:ttä oliota

// tai esim. (jos silmukkaa haluat siis käyttää)

std::vector<omaluokka> oliot; // voi olla esim. globaali määrittely, jos tosiaan sellaista haluat käyttää
for (int i = 0; i < 5; ++i)
    oliot.push_back(omaluokka(i));

--

Kuvailemallasi tavalla nimettyjä muuttujia et voi silmukassa luoda. Vastaavaan tarkoitukseen käytetään aina taulukoita tai taulukon kaltaisia muuttujia (kuten vectoria), ja indekseihin viitataan siis (mm.) syntaksilla muuttuja[N] (ei koskaan esim. muuttujaN)

Metabolix [15.04.2009 17:09:09]

#

Olennaiset ymmärrettävät asiat tässä ovat nämä:

1. Oliolla ei useinkaan ole ohjelman aikana nimeä, johon voisi viitata, vaan tuo "nimi" on vain koodissa esiintyvä sana, jolla kyseinen olio ohjelmoidessa ja käännettäessä yksilöidään. Nimet yleensä poistetaan linkityksen yhteydessä, koska sen jälkeen ne ovat turhia. Niitä voidaan poikkeuksellisesti säilyttää, jos niitä tarvitaan myöhemmin dynaamisen linkityksen yhteydessä (DLL-tiedostoissa) tai jos koodista on tallennettu erillistä debug-infoa debuggeria varten. Tällöinkin nimet on silti määritelty käännösvaiheessa eikä kesken ohjelman.

2. Käyttämäsi +-merkki ei missään tilanteessa voi tuottaa objektin nimeä, ja vain erityisten apuluokkien kanssa olisi muutenkaan mahdollista yhdistää luku +-merkillä johonkin (paitsi yhteenlaskussa).

Oikea ratkaisu ongelmaasi on luultavasti vector-luokan käyttö, kuten yllä esitettiin.

Vielä lähemmäs alkuperäistä koodiasi voisit päästä myös liittämällä ohjelmallisesti oliosi tiettyyn tekstiin tai lukuun. Tällöin voisit käyttää map-luokkaa ja tehdä sen ympärille tarvittavat apufunktiot:

#include <map>
#include <stdexcept>

class omaluokka {
	int muuttuja; // yms.
private:
	static std::map<int, omaluokka> oliot;
public:
	static omaluokka& luo(int i) {
		if (oliot.find(i) != oliot.end()) {
			throw std::runtime_error("Olio on jo!");
		}
		// Jos erityiset konstruktoriparametrit ovat tarpeen:
		// oliot[i] = omaluokka(x, y, z);
		return oliot[i];
	}
	static omaluokka& hae(int i) {
		if (oliot.find(i) == oliot.end()) {
			throw std::runtime_error("Oliota ei ole!");
		}
		return oliot[i];
	}
	static void tuhoa(int i) {
		if (oliot.find(i) == oliot.end()) {
			throw std::runtime_error("Oliota ei ole!");
		}
		oliot.erase(oliot.find(i));
	}
};
std::map<int, omaluokka> omaluokka::oliot;
for (int i = 0; i < 10; ++i) {
  omaluokka::luo(i);
}
omaluokka::hae(3).muuttuja = 10;
for (int i = 0; i < 10; ++i) {
  omaluokka::tuhoa(i);
}

Tämä ratkaisu ei luultavasti ole järkevä tarpeisiisi, mutta voit silti oppia tästä jotain mm. viittauksista (koodin &-merkit) ja luokkien staattisista jäsenistä.

Tampio [15.04.2009 18:29:33]

#

No voi veljet. Kai se täytyy kertoa enemmän taustoja ongelman takaa. Kehitysalustana on Visual Studio 2008, ja itseasiassa ensiksi koitin juuri luoda arrayta niille olioille, ja siinähän tuli joku mystinen ongelma jota sitten yritin kiertää tuolla alussa kuvailemallani tavalla. Arrayn sain tehtyä mielestäni tismalleen oikein, ohjelma kääntyi ja käynnistyikin nätisti, mutta kun array luodaan ja yrittää muuttaa yhden olion muuttujan arvoja, joko suoraan sijoittamalla tai kyseiseen luokkaan tehdyn funktion välityksellä, niin ohjelmahan kaatuu ja heittää virheilmoituksen "Object reference not set to an instance of an object". Luokan muodostimessa arvoja sai asetettua.
Arrayn loin näin:

array<omaluokka ^> ^ taulukko = gcnew array<omaluokka ^>(10);
taulukko[0]->muuttuja = "haloo"; //tässä kaatuu

Ongelma on kait jossain pintaa syvemmällä, joko ohjelmassa tai minun ymmärryksessäni. Täytyy tuota vectoria testata kunhan tästä kotiudun.

Metabolix [15.04.2009 18:41:30]

#

Nythän on niin, että luot tuossa taulukollisen osoittimia etkä lainkaan olioita niiden taakse. En tunne C++/CLI:a, mutta normaalin C++:n kanssa kehottaisin ottamaan osoitinmerkin (tässä tapauksessa ^-merkki) pois omaluokka-kohtien perästä ja käyttämään nuolen (->) sijaan pistettä.

array<omaluokka>^ taulukko = gcnew array<omaluokka>(10);

Jos tämä ei kyseisessä kielenkuvatuksessa ole mahdollista, joudut vielä luomaan nuo oliot silmukassa erikseen:

array<omaluokka^>^ taulukko = gcnew array<omaluokka^>(10);
for (int i = 0; i < 10; ++i) {
  taulukko[i] = gcnew omaluokka();
}

Miten on tuhoamisen tai muun vapauttamisen laita tuon GC:n kanssa, sitä en tiedä.

Jos taulukon koko tunnetaan, ei sitä varmaankaan kannata dynaamisesti varata:

array<omaluokka> taulukko(10); // vai kuinka lie?

Ja kun kerran C++/CLI on käytössä, mahtaako tuossa edes olla C++:n standardikirjastoa? Kannattaa muistaa, että C++/CLI on niin suurelta osin jo oma kielensä eikä C++:n laajennos, että tämäkin keskustelu sopisi oikeastaan paremmin muiden kielten alueelle. Korjasin otsikon todellisen kielen mukaiseksi.

Tampio [15.04.2009 22:17:14]

#

Metabolix kirjoitti:

Jos tämä ei kyseisessä kielenkuvatuksessa ole mahdollista, joudut vielä luomaan nuo oliot silmukassa erikseen:

array<omaluokka^>^ taulukko = gcnew array<omaluokka^>(10);
for (int i = 0; i < 10; ++i) {
  taulukko[i] = gcnew omaluokka();
}

No nyt. Tuon jälkeen homma toimii. Kiitos kovasti tästä, nyt kohti uusia vastoinkäymisiä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta