2016-09-15 12 views
1

Meine Situation ist also: Ich habe zwei Klassen: A, B. A enthält std::vector<B>, und B benötigt den Funktionszeiger von A, um seine eigenen Operationen zu initialisieren.Zeiger auf Elementfunktionen eines anderen Objekts

(Ich versuche, die Integer-Gruppe und integer Ring mathematische Strukturen in C++ zu implementieren)

Was der sicherste Weg dies zu tun ist? (Ich habe gelernt, dass das Geben von B ein Zeiger auf A unerwartetes Verhalten in A verursacht. Ich versuchte es here.)

Jetzt, dass ich an meinem Computer bin, werde ich meine Codebasis (Ich machte B-Mitgliedsklasse zu A, so als die Abschnitte zu minimieren ich muss abtippen):

Ah

#ifndef A_H 
#define A_H 

#include <vector> 

class A 
{ 
    public: 
     A(int); 
     static int defaultMultiply(int, int); 
     int multiply(int, int); 
     class B 
     { 
      public: 
       typedef int(*defaultMultiplication)(int, int); 
       typedef int(A::*multiplication)(int, int); 
       B(); 
       B(int, int, multiplication); 
       B operator*(const B&); 

      protected: 
       int m, parentGroupSize; 
       multiplication mult; 
       defaultMultiplication defMult; 

     }; 
    private: 
     int n; 
     std::vector<A::B> elements; 

}; 

#endif 

A.cpp

#include "A.h" 

#include <new> 

A::A() 
{ 

} 

A::A(int n) 
: n(n), elements(std::vector<A::B>(n)) 
{ 

} 

int A::defaultMultiply(int x, int y) { return (x * y); } 
// special multiplication: integer groups have integer addition modulo the group size as their multiplication 
int A::multiply(int x, int y) 
{ 
    int a = x % this->n, b = y % this->n; 
    if (a < 0) a += this->n; 
    if (b < 0) b += this->n; 
    return ((a + b) % n); 
} 

A::B::B() 
: m(0), 
    parentGroupSize(0), 
    mult(0), 
    defMult(&A::defaultMultiply) // right? 
{ 

} 

A::B::B(int m, int n, multiplication mult) 
: parentGroupSize(n), mult(mult), defMult(0) 
{ 
    // this->m must be in [0, g->size() - 1], if n is larger than 1 
    if (n > 1) 
    { 
     this->m = m % n; 
     if (this->m < 0) this->m = n + this->m; 
    } 
    else 
    { 
     this->m = m; 
    } 
} 

A::B A::B::operator*(const A::B& b) 
{ 
    if (this->parentGroupSize == b.parentGroupSize) 
    { 
     if (this->mult) 
     { 
      return A::B::B((this->*mult)(this->m, b.m), this->parentGroupSize, &A::B::mult); // I tried using this->mult for last argument, but it wouldn't take it 
     } 
    } 
    return A::B(); // or something similar 
} 

int A::B::val() const { return this->m; } 

main.cpp

#include <iostream> 

#include "A.h" 

using namespace std; 

int main() 
{ 
    A(26); // didn't implement any methods to get B's from A, since I am merely testing compilation. I'm trying for that ever-elusive MCVE with just this... 
} 

Oh, ich verstehe auch die folgende Fehlermeldung: error: pointer to member type 'int (A::)(int, int)' incompatible with object type 'A::B'

+4

Definieren Sie "sicherste". Bitte entfernen Sie auch alle irrelevanten Codes, die nichts mit der Frage zu tun haben. Ich bezweifle, dass die Details all dieser mathematischen Operationen in irgendeiner Weise für diese Frage relevant sind. –

+0

Wenn ein B oder A den Gültigkeitsbereich verlässt, treten keine Segmentfehler auf, z. B. weil entweder eine unendliche Zerstörungsschleife oder undichte Zeiger vorhanden sind. –

+0

Sie liefern den Grund, warum es so gemacht wird. –

Antwort

1

Ihr Problem ist nicht, dass Sie vorbei Mitglied-Funktion (als Argument) sind zu der Konstruktor eines Objekts eines anderen Typs als der Member-Function-Class-Typ; Das Problem ist, dass Sie Aufruf die Member-Funktion mit dem falschen Typ sind. Der Compiler-Fehler, den Sie bekommen, ist eigentlich ziemlich klar: ein Zeiger-zu-Mitglied muss mit dem gleichen Klassen-Typ verwendet werden, für den es deklariert wurde (oder ein abgeleiteter Typ), weil es sonst bedeutungslos wäre.

Beachten Sie, dass innere Klassen nicht abgeleitet Klassen sind; a B Objekt ist nicht eine spezialisierte Art von A. (Ich denke, Sie wissen das bereits, aber ich möchte klar sein.) Wenn Sie also versuchen, eine Methode A mit einer Objektinstanz vom Typ B aufzurufen, haben Sie nach etwas gefragt, das völlig unsinnig ist.

So gibt es zwei Möglichkeiten:

  • Verwenden Zeiger-to-Mitglied-of- B statt Zeiger-to-Mitglied-of A. Es gibt nie einen Grund, die Mitglieder mit Objekten des Typs A aufzurufen, daher ist unklar, warum Sie hier einen Zeiger-zu-Mitglied-von-A für nützlich hielten.
  • Verwenden Sie Nichtmitgliedszeiger. Beachten Sie, dass Ihr defaultMultiplication-Typ bereits eine Nichtmitgliedsfunktion ist. Beachten Sie, dass Nichtmitglieder weiterhin Instanzen von B als Argumente verwenden können; Sie haben nur eine viel einfachere Syntax.
+0

"ein Zeiger-zu-Mitglied muss mit demselben Klassen-Typ verwendet werden, für den es deklariert wurde, weil es sonst bedeutungslos wäre" - ziemlich sicher abgeleitete Typen sind in Ordnung. – xaxxon

+0

@xaxxon Nun, natürlich, wie in meinem zweiten Absatz, der besagt, dass abgeleitete Typen * Instanzen des Basistyps sind, zumindest aus der Perspektive der Verwendung von Zeigern zu Gliedern mit Zeigern zu Objekten. –

+0

Jemand kann aufhören zu lesen, wenn sie sehen, dass sie etwas nicht tun können - bevor sie zum nächsten Teil kommen, der besagt, dass der vorhergehende Teil nicht korrekt war. Könnte es auch von Anfang an richtig machen. Außerdem ist es eine Entschuldigung, das Wort "kovariant" zu verwenden. – xaxxon

Verwandte Themen