Zugriffsverweigerung

Takirion

Grünschnabel
Hallo allerseits, ich bin momentan dabei C++ zu lernen und im Zuge dessen habe ich angefangen die Spielregeln von "Das Schwarze Auge" zu implementieren (nichts ernstes, ich glaube nicht, dass ich das als Anfänger vollständig hinbekomme, aber irgendeine Aufgabe braucht man halt um die Sprache auszuprobieren). Bei der momentanen Imiplementierung tritt jetzt aber ein Laufzeitbug auf, dessen Ursache ich einfach nicht verstehe/finde.
C++:
DSA.h
#ifndef DSA
#define DSA

#include <string>
#include <vector>
#include <array>
#include <cstring>
#include <set>

using std::string;
using std::ostream;
using std::cout;

int d6();
int d20();

class Rundenzeit
{

};

class Modifikation
{
    string ausloeser;
    int hoehe;
    Rundenzeit beginn;
    Rundenzeit ende;
public:
    Modifikation(string slsr="Unbekannt", int h=0, Rundenzeit bgnn=Rundenzeit(), Rundenzeit nde=Rundenzeit());
    string Ausloeser()const{return ausloeser;};
    int Hoehe()const{return hoehe;};
    Rundenzeit Beginn()const{return beginn;};
    Rundenzeit Ende()const{return ende;};
    bool aktiv()const{return true;};
};


class Eigenschaft
{
    string name;
    int basiswert;
    std::vector<Modifikation> Modifikationen;
public:
    Eigenschaft(string nm, int bswrt=0);
    string Name()const{return name;};
    virtual int Basiswert()const{return basiswert;};
    virtual int Wert()const;
    int Probe()const{return Wert() - d20();};
    void addMod(Modifikation Mod);
    virtual operator int()const{return Wert();};
    virtual ~Eigenschaft(){};
};

class sEigenschaft : public Eigenschaft
{
    Eigenschaft *  GW[3];
public:
    sEigenschaft(string nm, Eigenschaft g1, Eigenschaft g2, Eigenschaft g3);
    virtual int Basiswert()const;
    void ptr1()const{cout<<(void*)GW[0];};
};

class Held
{
    string m_name;
    Eigenschaft mut;
    Eigenschaft klugheit;
    Eigenschaft intuition;
    Eigenschaft charisma;
    Eigenschaft fingerfertigkeit;
    Eigenschaft gewandtheit;
    Eigenschaft konstitution;
    Eigenschaft koerperkraft;
    sEigenschaft basisangriff;
    sEigenschaft basisparade;
    sEigenschaft magieresistenz;
    sEigenschaft basisfernkampf;
    sEigenschaft basisinitiative;
    int lebensenergie;
    int ausdauer;
    int astralenergie;

    enum {grundwert = 0};
    
public:
    Held::Held(string nm, int mu=grundwert, int kl=grundwert, int in=grundwert, int ch=grundwert, int ff=grundwert, int ge=grundwert, int ko=grundwert, int kk=grundwert);
    string name() const{return m_name;}
    int MU()const{return mut;}
    int KL()const{return klugheit;}
    int IN()const{return intuition;}
    int CH()const{return charisma;}
    int FF()const{return fingerfertigkeit;}
    int GE()const{return gewandtheit;}
    int KO()const{return konstitution;}
    int KK()const{return koerperkraft;}
    int AT()const{return basisangriff;}
    int PA()const{return basisparade;}
    int LE()const{return lebensenergie;}
    int AU()const{return ausdauer;}
    int AE()const{return astralenergie;}
    int MR()const{return magieresistenz;}
    void LEplus(int plus){lebensenergie += plus;}
    void angreifen(Held& Opfer);
    int parieren()const;
    friend ostream & operator<<(ostream & os, const Held & held);
};


#include "Definitionen.cpp"

#endif

C++:
Definitionen.cpp
#ifndef Definitionen
#define Definitionen

#include<string>
#include <iostream>
#include "DSA.h"

using std::string;
using std::cout;
using std::cin;
using std::ostream;

int d6()
{
    return (rand()%6)+1;
}

int d20()
{
    return (rand() % 20) + 1; 
}

//MODIFIKATIONSKLASSE

Modifikation::Modifikation(string slsr, int h, Rundenzeit bgnn, Rundenzeit nde)
{
    cout<<"Mod erstellt.";
    ausloeser=slsr;
    hoehe=h;
    beginn=bgnn;
    ende=nde;

}

//EIGENSCHAFTENKLASSE

Eigenschaft::Eigenschaft(string nm, int bswrt)
{
    name=nm;
    basiswert=bswrt;
    Modifikationen.resize(0);
}

int Eigenschaft::Wert()const
{
    int summe=(*this).Basiswert();
    for (unsigned int i=0; i<((*this).Modifikationen.size()); i++)
        if ((*this).Modifikationen[i].aktiv())
        summe+=Modifikationen[i].Hoehe();
    return summe;
}

void Eigenschaft::addMod(Modifikation Mod)
{
    (*this).Modifikationen.push_back(Mod);
}

//sEIGENSCHAFTSKLASSE

sEigenschaft::sEigenschaft(string nm, Eigenschaft g1, Eigenschaft g2, Eigenschaft g3): Eigenschaft(nm)
{
    GW[0]=&g1;
    GW[1]=&g2;
    GW[2]=&g3;
}

int sEigenschaft::Basiswert()const
{
    int sum=0;
    for(int iii=0; iii<3; iii++)
        sum+=((GW[iii])->Basiswert());
    return int((sum+2.5)/5);
}

// HELDENKLASSE

const string Eigenschaften[8] = {"Mut", "Klugheit", "Intuition", "Charisma", "Fingerfertigkeit", "Gewandtheit", "Konstitution", "Koerperkraft"};
const string sEigenschaften[5] = {"Attacke-Basiswert", "Parade-Basiswert", "Magieresistenz", "Fernkampf-Basiswert", "Initiative-Basiswert"};

Held::Held(string nm, int mu, int kl, int in, int ch, int ff, int ge, int ko, int kk): 
    mut(Eigenschaften[0], mu), klugheit(Eigenschaften[1], kl), intuition(Eigenschaften[2], in), charisma(Eigenschaften[3], ch), 
    fingerfertigkeit(Eigenschaften[4], ff), gewandtheit(Eigenschaften[5], ge), konstitution(Eigenschaften[6], ko), koerperkraft(Eigenschaften[7], kk),
    basisangriff(sEigenschaften[0], mut, gewandtheit, koerperkraft), basisparade(sEigenschaften[1], intuition, gewandtheit, koerperkraft), magieresistenz(sEigenschaften[2], mut, klugheit, konstitution), basisfernkampf(sEigenschaften[3], intuition, fingerfertigkeit, koerperkraft), basisinitiative(sEigenschaften[4], mut, mut, intuition)
{
    m_name=nm;
    lebensenergie=int((ko+ko+kk+1.0)/2);
    ausdauer=int((mu+ko+ge+1.0)/2);
    astralenergie=int((mu+in+ch+1.0)/2);
}
void Held::angreifen(Held& Opfer)
{
    cout<<"Möchtest du einen Wuchtschlag durchführen, " << m_name << " (y/n)? ";
    char entscheidung;
    cin>>entscheidung;
    short erschwernis=0;
    if(entscheidung == 'y')
    {
        cout<<"Um wie viel möchtest du die Probe erschweren? ";
        cin>>erschwernis;
    }
    short Angriffswurf = d20();
    short Verteidigungswurf = d20();
    short schaden;
    if (((Angriffswurf+erschwernis) < basisangriff.Wert())&&(0>Opfer.parieren()))
    {
        schaden = d6();
        Opfer.LEplus(-schaden);
        cout<< schaden << " Schaden verursacht. "<<Opfer.name() << " hat noch " << Opfer.LE() << " Lebensenergie.\n";
    }
    else
        cout<< "Kein Schaden verursacht.\n";

}



ostream & operator<<(ostream & os, const Held & held)
{
    os<< held.name() <<" ist ein epischer Held.\n\tMU " << held.MU() << "\tKL " << held.KL() << "\n\tIN " << held.IN() 
        << "\tCH " << held.CH() << "\n\tFF " << held.FF() << "\tGE " << held.GE() << "\n\tKO " <<held.KO() << "\tKK " 
        << held.KK() << "\n\tAT " << held.AT() << "\tPA " << held.PA() << "\n\tLE " << held.LE() << "\tAU " << held.AU() 
        << "\n\tMR " << held.MR() << "\tAE " << held.AE() <<"\n";
    return os;
}

int Held::parieren()const{return basisparade - d20();}

#endif

C++:
Haupt.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "DSA.h"
#include <string>


using std::cin;
using std::cout;
using std::string;



const int GRUNDKP = 100;
enum Dauer
{kurz=-1, normal, lang};


int main()
{

    cout<< "Gib den Spielernamen ein. "<<std::endl;
    string spielername;
    cin>>spielername;
    cout<< "Gib den Monsternamen ein."<<std::endl;
    string monstername;
    cin>>monstername;
    cout<<"Gib die gewünschten Grundwerte ein."<<std::endl;
    short Grundwert;
    cin>>Grundwert;
    Held spieler1(spielername, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert);
    Held monster1(monstername, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert, Grundwert);
    cout<<spieler1;
    cout<<monster1;
    do
    {
        spieler1.angreifen(monster1);
        if (monster1.LE() > 0)
            monster1.angreifen(spieler1);
        else
            break;
        cout<<spieler1;
        cout<<monster1;
    }
    while(spieler1.LE()>0);

    if (spieler1.LE()<=0)
        cout<<spieler1.name() <<" besiegt.";
    else
        cout<<monster1.name() <<" besiegt.";
    
    cin.get();
    cin.get();
    cin.get();
    return 0;
}

nachdem ich Spieler- und "Monster-"Namen, sowie den Grundwert eingegeben habe bricht das Programm ab mit der Meldung "Unbehandelte Ausnahme bei 0x00E56E0A in DSA Schnipsel.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xCCCCCCCC" und VS2012 zeigt mir in der Aufrufliste, dass die Funktionen main(), operator<<, Held::MR(), Eigenschaft::eek:perator int(), Eigenschaft::Wert() und sEigenschaft::Basiswert() aufgerufen sind und letztere bis zur Zeile
C++:
sum+=((GW[iii])->Basiswert());
fortgeschritten ist. Ich hatte erst vermutet, dass das Problem bei Privaten Members und Accesbeschränkungen durch die Klassen liegt, aber selbst wenn ich Held, Eigenschaft und sEigenschaft untereinander zu Friends mache (schon in allen Varianten ausprobiert) besteht der Fehler weiter. Ich hab inzwischen einfach keine Idee mehr was genau das Problem ist, außer dass es an der Tatsache liegen könnte, dass ich ein Objekt(Held) habe, die zwei andere Objekte (Eigenschaft und sEigenschaft) enthält, wovon eines (sEigenschaft) versucht mittels Pointer auf das andere (Eigenschaft) zuzugreifen.
Danke schonmal für alle Hilfe, ich befürchte ja, dass ich irgendeinen grundlegenden Fehler gemacht habe...
Lg
Takirion
 
Hi

Zurzeit seh ich da auch nichts.
Könntest du die fehlende(n) Datei(en) auch reinstellen,
damit ich das zum testen selbst kompilieren kann?
 
hm, also das mit dem Anhängen der Dateien klappt irgendwie nicht ("Ungültige Datei") und auch wenn ich das ganze Projekt rar verpacke und hochladen will heißt es, es sei fehlgeschlagen. Allerdings sind die drei Files, die ich schon gepostet habe alles, das momentan an Code im Projekt vorhanden ist (+die Ergänzung der Filenamen in der ersten Zeile). Alles andere sind irgendwelche von VS erstellten Projektdateien, die ja eigentlich darauf keinen Einfluss haben sollten.
 
Ah sorry, hab zuerst irgendwie nicht gemerkt dass die Definitionen.cpp
(die in Code 1 inkludiert wird) ja der zweite Codeteil ist :D

Werd mir das mal anschauen...

edit:
Ok, hatte in letzter Zeit wohl viel zu viel Java, um sowas zu übersehen :D

Wenn du irgendwas an eine Funktion übergibst, um dir drin einen Pointer abzuspeichern
(wie du zB. mit drei Parametern vom sEigenschaft-Konstruktor machst):
Eine "ganz normale" Parameterübergabe wie die dort kopiert das Objekt und übergibt die Kopie.
Die Kopie gilt im Konstruktor als lokale Variable (als würde man einfach ein "int i;" drin machen)
und wird am Konstruktorende wieder entfernt. ->Pointer darauf ist ab diesem Zeitpunkt wertlos.

Du brauchst eine Pointer auf das Originalobjekt.
Entweder direkt einen Pointer übergeben (Parametertyp mit *, übergeben mit &)
oder eine Referenz (Parametertyp mit &, übergeben normal).

Wo das Problem sonst noch so ist hab ich nicht gründlich gesucht;
die Sache mit dem sEigenschaft-Konstruktor war zumindest das aktuelle Absturzproblem.


Und du solltest dir überlegen, wie solche Held-Objekte etc. wieder weggeräumt werden.
Hier ists kein Problem, am main-Ende verschwindet einfach alles
(und Destruktor gibts glaub ich keinen (hab jetzt nicht nachgeschaut))
Aber wenn es größer wird und Objekte deiner Klassen auch während dem Programmdufchlauf
erzeugt und gelöscht werden: Welche Pointer von welchen Sachen werden dadurch ungültig?
Was muss gemacht werden, um die anderen Klassen wieder zu "reparieren"?
...Besser zuerst darüber nachdenken, damit das dann keine grausamen Hacks
über 100 Ecken erfordert.
 
Ok, vielen Dank. Fehler verstanden und (wie so oft) festgestellt, dass man das wissen Theoretisch gehabt hätte ;-) man is dann nur zu doof (und möglicherweise unerfahren mit pointern) es sauber anzuwenden ^^.
Bezüglich des Wegräumens: du sprichst davon, dass ich Objekte mit new erstelle und/oder new in Konstruktoren vorkommt (was ja auf das gleiche hinausläuft) bzw. diese auch mit delete (evt. im Destruktor) wieder lösche? Da habe ich mich bisher tatsächlich noch drum gedrückt, da das Aufräumen ähnlich viel Präzession erfordert wie die Arbeit mit Pointern und ich jetzt schon weiß, dass das zu hässlichen und vermutlich auch sehr unübersichtlichen Problemen führen wird. Aber demnächst wollte ich auch daran gehen :)
Vielen Dank auf jeden Fall nochmal für die Lösung meines Problems :)
 
Genau, für new´s auch delete´s.
Das nicht vorhanden ist effektiv ein Programmierfehler,
der nur in diesem "kleinen" Programm keine gravierenden Probleme macht.

Eben um das Hässlich-werden zu vermeiden sollte man möglichst früh dran denken :)
Dann gibts weniger Probleme damit, weil teilweise schon die Programmstruktur
evt. etwas anders wird, wenn man das in die Überlegungen mit einbezieht.

PS: Präzision?
 
Mit Präzision meinte ich, dass man äußerst leicht Fehler machen kann, die möglicherweise auch sehr schwer zu tracken sind wenn man sich nicht einen äußert genauen Plan macht in welchen Fällen news oder deletes genutzt werden können. Aber ich werde es vermutlich trotzdem versuchen :)

Dann allerdings die Frage: wo sollte ich in diesem Programm/in diesen Klassen new/delete verwenden? Erzeuge ich die Eigenschaftsobjekte in der Heldenklasse zur Laufzeit im Stiele von
Code:
 class Held
{
...
Eigenschaft * Eigenschaften[8]
...
}

Held::Held(string nm, int mu, int kl, int in, int ch, int ff, int ge, int ko, int kk)
{
...
Eigenschaften[0] = new Eigenschaft(Eigenschaften[0], mu); 
Eigenschaften[1] = new Eigenschaft(Eigenschaften[1], kl) 
...
}
und wenn ja, was ist der Vorteil gegenüber der momentanen Variante
 
Kann man so machen (nur, dass du in Zeile 11/12 das noch nicht erstellte Objekt
dem eigenen Konstruktor übergibst ist seltsam?)

Einer der Vorteile: Man kann selbst genau bestimmen,
wann Objekte erstellt werden und wie lange es sie gibt.
Bei der Lokalvariablenvariante ist das ja nur durch die Codestruktur beeinflussbar.
 
Zurück