为什么我的重载运算符不适用于派生类



我试图学习C++PL中的运算符重载。我做了一个如下所示的练习。我想做的是过载<lt;运算符,并在我的main中使用它。但无论何时,它都只适用于基类。这里有什么问题?

班级员工:

class Employee {
public:
string name;
int id;
int exp_level;
double salary;
Employee() {
this->name = "";
this->id = 0;
this->exp_level = 0;
this->salary = 0.0;
}
~Employee() {
//WTF
}
virtual void calculateSalary() {
//CODE
}

virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Employee& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << endl;
return os;
}
};

技术类:

class Technical : public Employee {
public:
string profession;
Technical() {
this->profession = "";
}
~Technical() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Technical& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Technical" << endl;
return os;
}
};

级工程师:

class Engineer : public Employee {
public:
Engineer() {
}
~Engineer() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Engineer& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Engineer" << endl;
return os;
}
};

主要方法:

int main()
{
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
cout << *e << endl;
cout << *t << endl;
cout << *ee << endl;    
}    

输出:

0 0 0
0 0 0
0 0 0

C++根据函数参数的静态类型选择最佳重载,因为在这种情况下类型是Employee,所以会调用Employeeoperator<<

如果你想让它在静态类型指针/引用与动态类型不匹配时调用正确的版本,你必须使用虚拟函数或使用dynamic_casts/typeid来检查具体的运行时类型(虚拟函数是imho最干净的方法(

示例:导螺杆

class Employee {
public:
virtual ~Employee() = default;
friend std::ostream& operator<<(std::ostream& os, const Employee& e) {
return e.put(os);
}
protected:
virtual std::ostream& put(std::ostream& os) const {
os << "Employee!";
return os;
}
};
class Technical : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Technical Employee!";
return os;
}
};
class Engineer : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Engineer Employee!";
return os;
}
};
int main() {
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
std::cout << *e << std::endl;
std::cout << *t << std::endl;
std::cout << *ee << std::endl;
delete ee;
delete t;
delete e; 
}

将导致:

Employee!
Technical Employee!
Engineer Employee!

还要记住,一旦类中至少有一个虚拟函数,那么析构函数几乎肯定也是虚拟的。

例如:

Employee* e = new Technical();
delete e;

如果析构函数不是虚拟的,则只调用~Employee(),而不调用~Technical()

因此,每当您想通过指向某个对象基类的指针删除该对象时,析构函数都需要是虚拟的,否则它就是未定义的行为。

由于这些声明

Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();

表达式*e*t*ee的静态类型是Employee &。所以运营商

friend ostream& operator<<(ostream& os, const Employee& e)

为所有三个对象调用。

一种简单的方法可以使友元运算符<lt"虚拟的";是在每个类中定义一个虚拟函数,例如

virtual std::ostream & out( std::ostream & ) const;

并定义像这样的(唯一(朋友运营商

friend ostream& operator<<(ostream& os, const Employee& e)
{
return e.out( os );
}

虚拟函数out需要在每个派生类中重新定义。

最新更新