假设我们有两个类:
class base{
protected:
char first_name;
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, base &client1)
{
char f_name[1001];
cout << "First Name: ";
in >> f_name;
client1=base(f_name); /// class parameterised constructor;
return in;
}
};
class derived: public base{
protected:
char last_name[1001];
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, derived &client2)
{
char l_name[1001], f_name[1001];
in >> (base) client2; /// it's not working like it dose in operator<<..
cout << "Last Name: ";
is >> l_name;
client2=derived(f_name, l_name); /// class parameterized constructor, 2 parameters because it use base constructor as well;
return in;
}
};
我重载了一些输出运算符(<<(,每次调用运算符<lt;从派生运算符<lt;。
我不知道这对运算符<lt;,我试了一下,但出了差错。当我调用基类运算符>gt;内部派生类运算符>gt;它给了我错误:
"对"operator>"的调用没有匹配函数>(std::istream&,abonament('|quot;
同样,如果我在运算符<lt,它运行良好:
friend ostream& operator << (ostream& out, derived &client)
{
out << (base) client; /// it's working;
out << client.last_name;
return in;
}
是否可以调用基类运算符>gt;内部派生类运算符>gt>为什么会发生这种情况以及如何解决?(我希望我不必在派生类运算符中再次重写基类运算符中的相同行(
您已经成为对象切片的牺牲品。您可以通过强制转换到引用来解决眼前的问题。
在中
in >> (base) client2;
真正发生的是从client2
生成一个新的临时Base
,丢弃derived
添加的所有成员。这是合法的。由于临时Base
不能用作base &client1
参数的参数,编译器会感到不安。临时变量就像它们听起来一样。它们存在的时间不长,所以引用一个是编译器阻止你犯的错误。如果它是合法的,临时变量将被Base
的>>
运算符修改,然后在您可以使用读取到它的内容之前立即超出范围
in >> (base&) client2;
不进行切片,也不生成临时变量。client2
更新成功。不幸的是,当
client2=derived(f_name, l_name);
用未初始化的变量CCD_ 9重写它。
因此,还需要更多的改变。
不要使用构造函数来完全重新创建和重新分配正在读入的对象。而是直接读取对象的成员变量。
示例:
class base{
protected:
char first_name[1001]; // need more than one character
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, base &client1)
{
// char f_name[1001]; don't need. Read into member
cout << "First Name: ";
in >> client1.first_name; // read directly into member
// client1=base(f_name); don't need. Work done above
return in;
}
};
class derived: public base{
protected:
char last_name[1001];
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, derived &client2)
{
//char l_name[1001], f_name[1001]; don't need. Use member variables
in >> (base&) client2; // client was being sliced. explanatory link above
// ^ fixed with reference to allow polymorphism
cout << "Last Name: ";
in >> client2.last_name; // fixed typo. reading directly into member
// client2=derived(f_name, l_name); don't need. Work done above
return in;
}
};
旁注:这是对继承的滥用。实际上,这是在说姓氏就是名字。事实并非如此。阅读利斯科夫替代原则,找到一个好的规则,帮助确定继承何时有意义。以下是一些入门读物:利斯科夫替代原则的一个例子是什么?
旁注:>>
向给定的char
数组中读取一个以空格分隔的标记,即一个单词。这里有两个问题。最重要的是它不知道什么时候该停下来。1001个字符的数组只能部分缓解这种情况。用户需要长时间键入以溢出缓冲区,但不要怀疑人们这样做是为了好玩或盈利。使用std::string
,问题就会消失。第二个问题是一个词的问题。这个解析器不能处理类似于"的名称;Billy Bob"或";von Doom";,幸运的是,这个姓氏的主人是虚构的,因为众所周知他是不可原谅的。