Virtual operetor = bylby tutaj bez sensu, bo sygnatury funkcji sa inne, przyjmuja one inne argumenty, czyli i tak mamy 2 rozne metody, wiec wywolanie polimorficzne i tak wybierze jedyna mozliwa opcje.
Zacznijmy od prostego przykładu:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(int a) : a(a){}
int a;
A& operator=(const A& arg) {
a = arg.a;
return *this;
}
};
class B : public A {
public:
B(int a, int b) : A(a), b(b) {}
int b;
B& operator=(const B& arg) {
b = arg.b;
return *this;
}
};
int main() {
B b(1,2);
B b2(3, 4);
b2 = b;
cout << b2.a << " " << b2.b << endl;
return 0;
}
Jak widzisz składowa a nie przekopiowała się, bo musielibyśmy wywołać jawnie operator= klasy bazowej:
A::operator=(arg);
Teraz już kopiowane jest wszystko.
Tak można tutaj zrobić polimorfizm, ale polimorfizm nie zadziała na lewym argumencie operatora, więc trzeba zrobić brzydki cast, a tego robić nie lubimy:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(int a) : a(a){}
int a;
virtual A& operator=(const A& arg) {
a = arg.a;
return *this;
}
};
class B : public A {
public:
B(int a, int b) : A(a), b(b) {}
int b;
//dodanie tutaj override wywali blad, bo to wcale nie jest przesloniecie
virtual B& operator=(const B& arg) {
A::operator=(arg);
b = arg.b;
return *this;
}
//tutaj mamy przesloniecie, sygnatura sie zgadza
virtual A& operator=(const A& arg) override {
cout << "juhu udalo sie" << endl;
//zawsze wejdziemy tutaj niezaleznie czy arg jest obiektem A lub B
//problem jest taki, ze nie wiadomo tutaj czy arg jest obiektem B czy A
//zeby to określić trzeba by zrobić brzydkiego dynamic_casta
a = arg.a;
try {
const B& argB = dynamic_cast<const B&>(arg);
b = argB.b;
}
catch (std::bad_cast& e) {
cout << "arg byl jednak typu A" << endl;
b = 69; //default value
}
return *this;
}
};
int main() {
A a(10);
B b(1,2);
A& aref = a;
A& bref = b;
bref = b;
bref = a;
return 0;
}