在嵌套 class 中对 operator[] 的调用不明确

Ambigous call for operator[] inside a nested class

我正在尝试制作一个具有向量特征的数据结构来学习一些 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();
    }
};

我在嵌套 class 中的 operator* 函数上收到了对重载函数的模糊调用。虽然我认为我遇到了问题(编译器如何知道它是否为 rhs/lhs),但我并不完全确定如何修复它。我想为此使用 operator[] 函数。

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

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

有什么建议吗?

您为 TestClass 定义的 operator[] 绝不会 "inherited" 或嵌套 class 中的 "embedded"。

您可以将 C++ 嵌套的 classes 视为普通的 classes,它们位于示例代码中的 "nested namespace": TestClass::NestedClass 中。

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


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

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

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

甚至不应该编译。

如果你 returned 一个 NestedClass 动态分配的实例 new,你应该 return 一个 指向它的指针 , 例如:

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

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

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

   NestedClass newNestedClass() {
        return NestedClass();
   }

编辑 2:适当的资源管理

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

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

class TestClass {
private:
    T* data;

public:
    ...

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

还要注意这段代码:

data = new T{t};

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

对应的清理代码为:

delete data;

但是,如果你想动态分配一个T的数组,语法是:

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

对应的清理语法为:

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

另请注意,如果您想在 class 中手动管理资源,您还应该考虑定义 复制构造函数 复制赋值 operator=()(见所谓的Rule of Three);如果你想实现移动语义,你还应该考虑实现移动构造函数移动赋值(在这种情况下,有一个相应的 "Rule of 5").

但是,如果您依赖于现有的 RAII 资源管理器,例如 std::vector,您就不必花费时间、精力和寻找错误来管理资源手动:全部自动std::vector或任何容器class管理] 你选择(在这种情况下,你有一个简单的 "Rule of Zero" :) 即编译器生成的默认复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符和析构函数会做紧的事情。

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