虚方法,operator =(),operator<<();

时间:2015-06-07 20:03:46

标签: c++ class inheritance objective-c++

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) 

2 个答案:

答案 0 :(得分:1)

operator =不是虚拟的,因为它未标记为virtualoperator =的声明看起来像这样

//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);,可以直接做到这一点。