class Port
{
private:
char * brand;
char style[20]; // i.e., tawny, ruby, vintage
int bottles;
public:
Port(const char * br = "none", const char * st = "none", int b = 0);
Port(const Port & p); // copy constructor
virtual ~Port() {delete[] brand; }
Port & operator=(const Port & p);
Port & operator+=(int b); // adds b to bottles
Port & operator-=(int b); // subtracts b from bottles, if
int BottleCount() const { return bottles; }
virtual void Show() const;
friend ostream & operator<<(ostream & os, const Port & p);
};
class VintagePort : public Port // style necessarily = "vintage"
{
private:
char * nickname; // i.e., "The Noble" or "Old Velvet", etc.
int year; // vintage year
public:
VintagePort();
VintagePort(const char * br, const char *st, int b, const char * nn, int y);
VintagePort(const VintagePort & vp);
~VintagePort() { delete[]nickname;}
VintagePort & operator=(const VintagePort & vp);
virtual void Show() const;
friend ostream & operator<<(ostream & os, const VintagePort & vp);
};
我必须解释为什么operator=()
和operator<<()
不是
虚拟。我认为operator<<()
不能是虚拟的,因为只有类方法可以,但我不知道operator =()。基本类的指针如何知道它必须使用哪个operator=()
?
第二个问题是我如何使operator<<()
表现得像虚拟方法:
basicClass B;
inheritClass I;
basicClass *ptr;
ptr=&I;
std::cout << ptr // Here I'd like to use operator<<(std::ostream, inheritClass)
答案 0 :(得分:1)
operator =
不是虚拟的,因为它未标记为virtual
。 operator =
的声明看起来像这样
//No virtual here
Port& operator =(const Port&);
但是,如果operator =
是虚拟的,它将被声明为
virtual Port& operator =(const Port&);
^^^^^^^ Virtual here!
由于operator =
不是虚拟的,编译器在编译时会使用静态链接。这意味着调用的函数取决于它所引用的变量的类型。请考虑以下代码:
VintagePort vp;
//Calls VintagePort::operator =(const VintagePort&)
vp = VintagePort();
Port* p = &vp;
//Calls Port::operator =(const Port&)
*p = Port();
VintagePort::operator =
在以VintagePort
进行访问时被调用,但是Port::operator =
在作为Port
访问时被调用。 (实例here。)
要使operator <<
表现得像虚拟一样,您必须在类中声明执行打印的虚拟成员函数。像这样的东西
//Inside Port
virtual void Print(std::ostream& os) const
{
os << brand << ' ' << style << ' ' << bottles;
}
然后在每个派生自Port
的类(如VintagePort
)中,您将覆盖该方法以打印该派生类的值。因此对VintagePort
你可以做到这一点
//Inside VintagePort
void Print(std::ostream& os) const
{
//Make Port print first
Port::Print(os);
os << ' ' << nickname << ' ' << year;
}
然后在operator <<
中你所要做的就是在参数上调用Print
方法。看起来像这样:
std::ostream& operator <<(std::ostream& os, const Port& p)
{
P.Print();
return os;
}
作为一个优点,您不必为每个派生类重载operator <<
,因为重载只需要Port
类中的虚函数。
答案 1 :(得分:0)
这有codereview的感觉,这不是SO的用途 - 但无论如何:
不要使用字符数组。使用std::string
:
class Port
{
private:
std::string brand;
std::string style; // i.e., tawny, ruby, vintage
//...
};
此外,通常,不要使用对象适当的指针。如果你需要指针,使用智能指针来清楚地表达目的。
这是支持C ++大部分内容的 RAII 原则。
如果您遵循上一个建议,则无需定义:析构函数,复制/移动构造函数,以及 - 触及您的问题 - 也不是赋值运算符。 (特别是,没有必要重载后者)。
operator<<
不能声明为virtual
,因为它不是类成员。这是一个独立的功能,由于是朋友,可以访问您的葡萄酒类的私人成员。
但你可以在课外重载它。通过将不同的重载设置为operator<<(ostream & os, const Port & p);
和operator<<(ostream & os, const VintagePort & p);
,可以直接做到这一点。