Próbuję zbudować klasę szablon {X0}} za pomocą konstruktora, który akceptuje 4 parametry jako 4 podłoże a
, {x2}}, c
, d
zajmująca Cztery ćwiartki (a
= Northwest, b
= Northeast, c
= Southwest, d
= południowo-wschodnia) macierzy. Pokazane poniżej:
template<class T> class SquareMatrix {
public:
SquareMatrix(){}
SquareMatrix(const T first, const T second, const T third, const T fourth) {
a = first;
b = second;
c = third;
d = fourth;
}
SquareMatrix<T>(const SquareMatrix<T>& rhs) { // copy constructor
a = rhs.getA();
b = rhs.getB();
c = rhs.getC();
d = rhs.getD();
}
SquareMatrix& operator=(const SquareMatrix rhs) { // assignment operator
if (&rhs != this) {
SquareMatrix(rhs);
}
return *this;
}
~SquareMatrix() {} // destructor
// getters and setters
T getA() const {return a;}
T getB() const {return b;}
T getC() const {return c;}
T getD() const {return d;}
void setA(const T& input) {a = input;}
void setB(const T& input) {b = input;}
void setC(const T& input) {c = input;}
void setD(const T& input) {d = input;}
private:
// 4 quadrants
// [a, b;
// c, d]
T a, b, c, d;
};
template<class T> SquareMatrix<T> operator+(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() + rhs.getA() );
ret.setB( ret.getB() + rhs.getB() );
ret.setC( ret.getC() + rhs.getC() );
ret.setD( ret.getD() + rhs.getD() );
return ret;
};
template<class T> SquareMatrix<T> operator-(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() - rhs.getA() );
ret.setB( ret.getB() - rhs.getB() );
ret.setC( ret.getC() - rhs.getC() );
ret.setD( ret.getD() - rhs.getD() );
return ret;
};
// this is the implementation of Strassen's algorithm
template<class T> SquareMatrix<T> operator*(const SquareMatrix<T>& lhs,
const SquareMatrix<T>& rhs) {
T product_1 = lhs.getA() * ( rhs.getB() - rhs.getD() );
T product_2 = ( lhs.getA() + lhs.getB() ) * rhs.getD();
T product_3 = ( lhs.getC() + lhs.getD() ) * rhs.getA();
T product_4 = lhs.getD() * ( rhs.getC() - rhs.getA() );
T product_5 = ( lhs.getA() + lhs.getD() ) * ( rhs.getA() + rhs.getD() );
T product_6 = ( lhs.getB() - lhs.getD() ) * ( rhs.getC() + rhs.getD() );
T product_7 = ( lhs.getA() - lhs.getC() ) * ( rhs.getA() + rhs.getB() );
SquareMatrix<T> ret;
ret.setA(product_5 + product_4 - product_2 + product_6);
ret.setB(product_1 + product_2);
ret.setC(product_3 + product_4);
ret.setD(product_1 + product_5 - product_3 - product_7);
return ret;
};
Teraz próbuję utworzyć zagnieżdżoną matrycę 4x4, robiąc:
int main() {
cout << "Example: a 4x4 matrix: " << endl;
// 4 single quadrants
SquareMatrix<int> M_1A(1, 2, 3, 4);
SquareMatrix<int> M_1B(5, 6, 7, 8);
SquareMatrix<int> M_1C(9, 10, 11, 12);
SquareMatrix<int> M_1D(13, 14, 15, 16);
// 4x4 matrix M_1
SquareMatrix< SquareMatrix<int> > M_1(M_1A, M_1B, M_1C, M_1D);
// test
cout << "test: " << endl;
cout << M_1.getA().getA() << endl;
return 0;
}
Zamierzona wyjście macierzy powinno być M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16]
. Używam polecenia {{X1} (Ostatni raz próbowałem, dał 6684672). Czy istnieje sposób na wdrożenie klasy matrycy w ten sposób?
(Edytuj: Obecnie zawarte operator przydzielania i destruktor, prawdopodobne źródła błędu)
2 odpowiedzi
Wraz ze sugerowanymi komentarzami jest operator przydziałowy, który jest uszkodzony.
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix(rhs); // <-- This creates a temporary that
// dies off after that line is executed
}
return *this;
}
Operator przydziału nie wykonuje żadnych przydziału. Zamiast tego dokonano tymczasowego SquareMatrix
.
Naprawić ten problem
1) Nie dostarczaj żadnych operatora przypisywania, konstruktora kopiowania lub destruktora, ponieważ typ T
powinien być bezpiecznie kopiowania.
2) Napraw operator przypisania, aby poprawnie działa:
#include <algorithm>
//...
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix t(rhs);
std::swap(t.a, a);
std::swap(t.b, b);
std::swap(t.c, c);
std::swap(t.d, d);
}
return *this;
}
Przypisanie działa teraz. Jednak sugeruję, że nie pisze kod, który nie musi być napisany, a twoja implementacja buggy jest w punkcie.
W twoim przypadku, jeśli pozwolisz kompilatorowi wygenerować operatora przypisania i / lub polegać na T
w szablonie, aby mieć poprawne semantyki kopii, Twoja klasa będzie działała poprawnie.
Komentarze Pawła są tuż przy znaku. Chociaż twój Squarexix nie jest wbudowany, jest zadeklarowany składa się z 4 elementów typu T. Domyślna kopia C'tor dla Twojej klasy będzie używana operatora przydziału lub przypisania C'tor o rzeczywistym rodzaju, który jest reprezentowany W twoim użyciu.
Mam pewne sugestie, aby ulepszyć kod:
- Jeśli T ma typ, który ma ślad pamięci, który jest większy niż wskaźnik / Int: bardziej wydajny jest pozwolenie, aby Twój C'tor otrzymał elementy Bij Const Reference taka:
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
- Użyj konstruktorów kopiowania jak najwięcej: w ten sposób cztery elementy nie są pierwsze zainicjowane, a następnie przypisane później. Zamiast tego są inicjalizowane z odpowiednimi wartościami na raz.
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
: a( _a), b( _b), c( _c), d( _d)
{ /* empty body */ }
- Wybierz swoje nazwy mądrze, aby uprościć rzeczy. Nie wprowadzaj dodatkowych mapów w schematach nazw, kiedy nie musisz; Właśnie stwarza możliwości poślizgu. Zastosowałem już, że w pkt 1 powyżej :-).
- Nie "Programuj przez życzeniowe myślenie": Pisanie w komentarzach lub nazwach typu / zmienne, które coś ma być coś, czego nie będzie tego zrobić. W twoim przypadku: Twoja klasa nie jest matrycą kwadratową, ani nawet matrycą. Do kompilatora jest typem danych składający się z czterech elementów, odpowiednio o nazwie A, B, C i D, o typ T, który należy zdefiniować w czasie kompilacji.
Podobne pytania
Nowe pytania
c++
C ++ to język programowania ogólnego przeznaczenia. Pierwotnie został zaprojektowany jako rozszerzenie C i ma podobną składnię, ale teraz jest to zupełnie inny język. Użyj tego tagu w przypadku pytań dotyczących kodu (który ma zostać) skompilowany za pomocą kompilatora C ++. Użyj znacznika specyficznego dla wersji w przypadku pytań związanych z określoną wersją standardu [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] lub [C ++ 23] itp. .