我试图学习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
,所以会调用Employee
的operator<<
。
如果你想让它在静态类型指针/引用与动态类型不匹配时调用正确的版本,你必须使用虚拟函数或使用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
需要在每个派生类中重新定义。