【问题标题】:Ambigous call for operator[] inside a nested class在嵌套类中对 operator[] 的模糊调用
【发布时间】:2015-02-23 08:52:51
【问题描述】:

我正在尝试制作一个具有矢量特征的数据结构来学习一些 C++。我目前正试图编译类似这样的代码:

template<typename T>
class TestClass {
public:
    T* data;
    TestClass(const T& t) { 
        data = new T{ t };
    }
    ~TestClass(void) {}
    TestClass(const TestClass&) {}

    T& operator[](int k) { return *data; }
    const T& operator[](int k) const { return *data; }
    class NestedClass {
    public:
        NestedClass(void) {}
        ~NestedClass(void) {}
        T& operator*(void) { return operator[](0); }
    };

    NestedClass newNestedClass(void) {
        return new NestedClass();
    }
};

我在嵌套类中的operator* 函数上收到了对重载函数的模棱两可的调用。虽然我认为我得到了问题(编译器如何知道它的 rhs/lhs)我不完全确定如何解决它。我想为此使用operator[] 函数。

我希望这两条打印行打印完全相同的内容:

TestClass<int> t(1);
auto n = t.newNestedClass();
cout << t[0] << endl;
cout << *n << endl;
return 0;

有什么建议吗?

【问题讨论】:

  • 问题是operator[]不是NestedClass的成员。您必须自己提供一个对象参数。例如。保存指向TestClass 的指针。
  • 嵌套类只是一个单独命名空间中的普通类,外部类提供命名空间。除此之外,它与外部类没有特殊联系,就像(我认为)在 Java 中一样。
  • 谢谢!我不熟悉这个概念。

标签: c++ operator-overloading nested-class ambiguity


【解决方案1】:

您为TestClass 定义的operator[] 绝不是“继承”或以某种方式“嵌入”到您的嵌套类中。

您可以将 C++ 嵌套类视为普通类,它们存在于“嵌套命名空间”中:示例代码中的 TestClass::NestedClass

如果你想为你的嵌套类创建一个operator[],你必须从头开始定义一个(就像你为你的TestClass所做的那样)。


编辑 1:返回类(C++ 不是 Java)

另请注意,C++ 不是,例如Java(使用new 分配类实例的模式,并依靠垃圾收集器自动收集“垃圾”)。
所以,像这样的代码:

   NestedClass newNestedClass(void) {
        return new NestedClass();
    }

甚至不应该编译。

如果您返回一个使用new 动态分配的NestedClass 实例,您应该返回一个指向它的指针,例如:

   // Note the "*" for the returned pointer
   NestedClass* newNestedClass() {
        return new NestedClass();
   }

但是,这更像是一种 Java 模式。

在 C++ 中,您可能只想返回一个 NestedClass 的实例没有 new 动态分配;这应该可以正常工作:

   NestedClass newNestedClass() {
        return NestedClass();
   }

编辑 2:正确的资源管理

另请注意,您可能希望将T* data; 成员设为private,以便更好地封装和信息隐藏。您正在提供适当的 public 访问器(如 operator[] 重载)来访问您的类的数据:公开访问器成员函数,而不是数据成员。

此外,您动态地 使用new 在堆上分配了data。您必须释放动态堆分配的内存,以避免内存(和资源)泄漏
这样做的好地方是你的类析构函数,例如:

class TestClass {
private:
    T* data;

public:
    ...

    ~TestClass() {
        // Release resoruces dynamically allocated
        delete data;
    }
}

还要注意这段代码:

data = new T{t};

只是动态分配T的单个实例,将其初始化为值t

对应的清理代码为:

delete data;

但是,如果要动态分配Ts的数组,语法是:

data = new T[elementCount];
// ... initialize data to some value...

对应的清理语法为:

delete[] data; // Note the []!!

还要注意,如果你想在你的类中手动管理资源,你还应该考虑定义 copy constructorcopy assignment operator=()(参见所谓的Rule of Three);如果你想实现move语义,你还应该考虑实现move constructormove assignment(在这种情况下有一个对应的 “5 规则”)。

但是,如果您依赖已经可用的 RAII 资源管理器,例如 std::vector,您就不必花费时间、精力和寻找错误来手动管理资源:这一切都由 std::vector 或您选择的任何容器类自动管理(在这种情况下,您有一个简单的“零规则” em> :) 即默认的编译器生成的复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符和析构函数将执行严格的操作。

但是,当然,如果这是一个学习练习,您可能希望自己实现那些特殊的成员函数。

【讨论】:

  • 感谢您在编辑部分的提醒。在我解决了最初的问题后,我发现了这个编译错误:)
猜你喜欢
  • 2019-12-14
  • 1970-01-01
  • 2019-03-23
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 2019-12-21
  • 1970-01-01
  • 2015-07-17
相关资源
最近更新 更多