【问题标题】:Unexpected out (virtual function returning string)出乎意料(虚函数返回字符串)
【发布时间】:2021-08-01 07:46:58
【问题描述】:

我在以下简单代码中遇到了一些意外输出问题。输出在基类上运行良好,但由于某种原因我在派生类上遇到了麻烦。

#include <iostream>
#include <string>
using namespace std;


class vehicle {
public:
    string* name;
    vehicle() {}
    vehicle(const string& inputName) {name = new string(inputName);} //constructor
    virtual ~vehicle() {delete name; name = nullptr;} // always make base class destructor virtual
    //vehicle(const vehicle& rhs) {*this = rhs; cout << "copy called" << endl;} //copy constructor
    vehicle& operator=(const vehicle& rhs) {
        cout << "assignment called" << endl;
        if(this == &rhs){
            return *this;
        }
        name = new string(*rhs.name);
        return *this;
    } //assignment operator
    virtual string& getName() const {return *name; cout << "base" << endl;} //mark function const if we are not going to make any changes to the object
};

class car : public vehicle {
    string *title = new string;
public:
    car() : vehicle() {}
    car(const string& inputName) : vehicle(inputName) {*title = inputName;}
    virtual ~car() {}
    virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}
};
int main() {

    car test("honda");
    string temp;
    temp = test.getName();
    cout << temp;

    return 0;
}

我打算得到以下输出:

honda

但我得到了:

~weird square boxes~

编辑:

我真正想要完成的是派生类中的以下内容:

virtual string& getName() const {return "Car: " + *name;} 

在我因为使用​​堆作为字符串而发火之前,请知道我只是在这里做实验。据我了解,这在理论上应该可行。

【问题讨论】:

  • 您正在返回对临时的引用。坏事会发生。
  • 为什么是nametitle 指针?
  • string *title = new string; 删除 * 并修复所有取消引用 title 的使用。它不应该是一个指针
  • 一般来说,指向string 的指针没那么有用。在它的最基本形式中,string 是一个指针和一个计数,通过在组合中添加另一个指针你什么也得不到。动态分配字符串也是一个糟糕的举动。 strings 的工作是为您处理动态分配的细节。如果您发现自己遇到需要自行管理分配的问题,string 可能不是适合这项工作的工具。
  • C++ 不是 Java。停止使用 new 关键字。

标签: c++ class inheritance polymorphism virtual-functions


【解决方案1】:

这个函数

virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}

调用未定义的行为,因为它返回对本地对象 temp 的引用,该对象在退出函数后将不再存在。

你可以像这样定义函数

virtual const string& getName() const {return *name;}

const string& getName() const override { return *title;}

并且return语句后面的语句没有作用。

您的其他代码也有缺点。例如,复制赋值运算符会产生内存泄漏。

或者您需要明确定义汽车类的析构函数。

请注意,将数据成员nametitle 声明为指向std::string 类型对象的指针是没有意义的。而是声明std::string 类型的数据成员。

【讨论】:

  • 你能解释一下为什么复制赋值运算符会产生内存泄漏吗?显式定义 car 的复制构造函数并不能解决问题: virtual ~car() {vehicle::~vehicle();删除标题;标题 = nullptr;}
猜你喜欢
  • 2018-02-14
  • 2015-11-10
  • 1970-01-01
  • 2015-06-18
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
相关资源
最近更新 更多