在嵌套 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" :) 即编译器生成的默认复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符和析构函数会做紧的事情。
但是,当然,如果这是一个学习练习,您可能希望自己实现那些特殊的成员函数。
我正在尝试制作一个具有向量特征的数据结构来学习一些 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" :) 即编译器生成的默认复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符和析构函数会做紧的事情。
但是,当然,如果这是一个学习练习,您可能希望自己实现那些特殊的成员函数。