Я создал минимальный пример, который, как мне кажется, демонстрирует ваши проблемы.Надеюсь, это также иллюстрирует комментаторам, что вы пытаетесь достичь.
#include <iostream>
#include <complex>
#include <string>
class cd: public std::complex<double> {
public:
cd(double re, double im):std::complex<double>(re,im),name("var1"){}
operator double(){
if (imag()==0.0) return real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
private:
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
, который дает следующий вывод из g++
(версия 7.4.0)
test_complex_double.cc: In function ‘int main()’:
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:22:4: note: candidate 2: cd operator*(const int&, const cd&)
cd operator*(const int& i, const cd& z){
^~~~~~~~
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:26:4: note: candidate 2: cd operator*(const double&, const cd&)
cd operator*(const double& x, const cd& z){
^~~~~~~~
Это всего лишь предупреждение, и этот пример все еще компилируется.
Я думаю, что решение состоит в том, что вы хотите, чтобы ваш класс был контейнером для std::complex<double>
, а не наследовался от него.Я предполагаю, что вы хотите наследовать, чтобы вам не приходилось реализовывать функции-оболочки вокруг всего, что реализует std::complex<double>
, но контейнерный подход, на мой взгляд, имеет больше смысла, а также решает эту конкретную проблему.
Вот рабочий пример, показывающий альтернативу контейнера:
#include <iostream>
#include <complex>
#include <string>
class cd {
public:
cd(double re, double im):val(re,im),name("var1"){}
cd(const std::complex<double>& v):val(v),name("var1"){}
operator double(){
if (val.imag()==0.0) return val.real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
double real() const{return val.real();}
double imag() const{return val.imag();}
cd operator*(const cd& other)const{return val*other.val;}
private:
std::complex<double> val;
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
Компилируется без предупреждений, и при запуске программы выводится:
var1=(2,4)
var1=(30,60)
foo 90
var1=(3,6)