Klasse



  • class A {
    
    public : 
    
    funk();
    
    }
    
    class B:public A {
    
    public:
    
    funktion();
    
    }
    
    int main() {
    
    B objekt;
    A* ptr =&objekt;
    
    }
    

    Also obwohl das Objekt die memberfunktion Funktion hat, kann der Zeiger ptr
    nicht draufzugreifen. Ist doch auch irgendwie blöd oder ?? warum nimmt
    man nicht einfach einen B* ptr ?? Der Compiler meckert jedenfalls bei
    beiden nicht. Jedenfalls kann ich über ptr->funktion() nicht zugreifen obwohl
    objekt diese Funktion hat



  • Hallo,

    Das ist nunmal so. Woher soll A denn die Funktionen von B kennen. Wenn es unbedingt sein muss kann man ja casten.
    Welche Frage hast du jetzt genau?



  • blurry333 schrieb:

    warum nimmt
    man nicht einfach einen B* ptr ??

    Ja, das solltest du dann auch machen, wenn du Funktionen nutzen willst, die nur für B sinnvoll sind.
    Sind die Funktionen auch für A's sinnvoll, dann muss die Funktion halt schon in A sein.



  • Hiho,

    hierbei ist es so, dass der Datentyp des Pointers (A) ausschlaggebend ist,
    und 'A' kennt nun mal keine Methode namens "funktion",
    deshalb müsstest du casten.

    In deinem Fall solltest du sogar

    B* ptr =&objekt;
    

    nehmen, da deine Basisklasse nicht Polymorph ist und die beiden Methoden auch unterschiedliche Namen haben.

    Davon abgesehn solltest du dir nochmals die Syntax anschauen,
    und dein Quellcode ordentlich gestalten, d.h. u.a. einrücken:

    class A
    {
        public:
            void funk() {}
    };
    
    class B:public A
    {
        public:
            void funktion() {}
    };
    
    int main()
    {
        B objekt;
        A* ptr =&objekt;
    
        return 0;
    }
    

    hoff das hilft 😉



  • blurry333 schrieb:

    Also obwohl das Objekt die memberfunktion Funktion hat, kann der Zeiger ptr nicht draufzugreifen. Ist doch auch irgendwie blöd oder ?? warum nimmt man nicht einfach einen B* ptr ??

    Deine Frage scheint mit etwas anderer Natur zu sein, vermutlich hast du ähnliches in irgendwelchen Code gesehen.

    Wenn man einen Basisklassenzeiger verwendet, tut man dies in der Regel aus guten Grund, und in Zusammenhang mit Polymorphie (mehrere Klassen teilen sich eine gemeinsame Schnittstelle, und werden über diese gemeinsame Schnittstelle verwendet). In deinen Beispiel macht dies kein Sinn, aber mit virtuellen Funktionen (und entweder einem virtuellen, oder einen privaten Destruktor in der Basisklasse) schon.



  • wenn beide klassen die methode funk() hätten
    und ich in der Basisklasse diese Methode virtual mache,
    dann kann ein Basisklassenzeiger plötzlich trotzdem drauf
    zugriefen obwohl er grundsätzlich diese funktion in der abgeleiteten klasse
    gar nicht kennt. Aber auf andere funktionen in der abgeleiteten klasse
    kann er nicht zugreifen?



  • hiho,

    Wenn eine Klasse min.1 virtuelle Methode hat, dann ist sie polymorph.
    Es wird nun erst zur Laufzeit entschieden, welche Methode schlussendlich aufgerufen wird (late binding).

    Virtuelle Methoden können von der Subklasse überschrieben werden.
    Ist dies der Fall, wird die Methode der Subklasse aufgerufen (late binding).



  • blurry333 schrieb:

    wenn beide klassen die methode funk() hätten
    und ich in der Basisklasse diese Methode virtual mache,
    dann kann ein Basisklassenzeiger plötzlich trotzdem drauf
    zugriefen obwohl er grundsätzlich diese funktion in der abgeleiteten klasse
    gar nicht kennt. Aber auf andere funktionen in der abgeleiteten klasse
    kann er nicht zugreifen?

    Bitte unterlasse das umbrechen per Return inmitten von Absätzen, das Forum bricht automatisch um.

    Grundsätzlich ist ein Zeiger erst einmal nur eine Adresse und zeigt auf einen bestimmten Typ. Der Zeiger selbst weiß nicht, ob du ihn eine Abgeleitete Klasse vorsetzt - ansonsten müsste er alle Methoden aller Klassen die von diesem Typ abgeleitet werden anbieten, und das wäre Schwachsinn.

    Bei virtuellen Methoden wird aber immer die "richtige" Methode ausgeführt, sprich die, die ausgehend von der Konkreten Klasse am "nächsten" implementiert wurde. Bei einer nicht virtuellen Methode wird über den Zeigertyp die passende gewählt (Sprich die Methode die vom Typ auf den der Zeiger verweist ausgehend die "nächst" höhere ist). Ich verdeutliche dies mal wie folgt:

    class A
    {
        public:
            virtual ~A() {}
            void foo1() { std::cout << "A::foo1\n"; }
            virtual foo2() { std::cout << "A::foo2\n"; }
    };
    
    class B : public A
    {
        public:
            void foo1() { std::cout << "B::foo1\n"; }
            virtual foo2() { std::cout << "B::foo2\n"; }
    };
    
    class C : public B
    {
        public:
    }
    
    class D : public C
    {
        public:
            void foo1() { std::cout << "D::foo1\n"; }
            virtual foo2() { std::cout << "D::foo2\n"; }
    }
    
    // Aus Gründen der einfachheit verwende ich hier eine Referenz, kann
    // man aber auch mit einen Zeiger machen.
    void doFooA(
        A & a)
    {
        a.foo1();
        a.foo2();
    }
    
    void doFooC(
        C & a)
    {
        c.foo1();
        c.foo2();
    }
    
    int main()
    {
        A a;
        B b;
        C c;
        D d;
        doFooA(a);
        doFooA(b);
        doFooA(c);
        doFooA(d);
        doFooC(c);
        doFooC(d);
    }
    

    Ergebnis von doFooA: Bei foo1 immer die "A::foo1" Ausgabe, und bei foo2 A, B, B, D (C hat keine eigene, daher die nächste [B] in der Hierarchie nach oben).

    Ergebnis von doFooB: Bei foo1 immer die "B::foo1" Ausgabe [nächste von C aus in der Hierarchie nach oben], und bei foo2 B, D (C hat keine eigene, daher die nächste [B]).


Log in to reply