0

我在 C++/CLI 中遇到了一些与我认为我知道的相反的东西:

通常,如果你将一个对象传递给一个函数,你会使用一个点来访问它的方法(这也适用于ref类,带有一些额外的构造函数):

value class Value {
  void Print() { Console::WriteLine("Value"); }
};

void f(Value v) {
  v.Print();
}

通常,通过接口将对象传递给函数会强制您将 a^放在参数上,并->在方法调用中使用:

interface class Base {
  void Print();
};

void f(Base ^b) {
  b->Print();
}

但是,如果您f使用基于接口的约束进行泛型,编译器会坚持您使用->,但也坚持您不要^在参数列表中使用:

interface class Base {
  void Print();
};

generic <class T> where T : Base
void f(T t) {
  t->Print();
}

到目前为止,我认为直接引用对象总是使用.,通过句柄引用它们总是使用->. 这似乎直接使用 a 引用一个对象->- 我错了什么?

4

2 回答 2

1

他们试图使 C++/CLI 语法与 C++ 语法等效,但这并不是特别成功。规则是你.用来访问一个值类型的成员,->来访问一个引用类型的成员。

第一个复杂的问题是堆栈语义。您可以放下帽子来声明引用类型的局部变量。然后自动在作用域块的末尾释放,编译器自动生成一个析构函数调用。试图使托管类型的行为类似于 C++ 类型并挽救 RAII 模式。

第二个问题是编译器允许在值类型的变量上使用帽子。这是 99% 的类型错误,特别令人讨厌,因为这在运行时非常昂贵,因为值被装箱了。

泛型使它最终变得模棱两可,类型参数可以是值类型或引用类型。这将使具体类型成为值或引用类型,直到运行时才被整理出来。请注意,在您的示例中这是允许的,值类型可以实现接口。那么规则是你总是在类型参数的变量上不加帽子地编写代码,将它们视为值类型。但是使用箭头取消引用这些变量,就好像它们是引用类型引用一样。是的,非常混乱。

于 2012-05-21T17:44:01.137 回答
0

到目前为止,我认为直接引用对象总是使用.,通过句柄引用它们总是使用->. 这似乎直接使用 a 引用一个对象->- 我错了什么?

你的第一句话是完全正确的。对于您的第二句话....您没有直接访问对象。 T本身将是一个句柄类型,例如String^.

您使用额外的复制构造函数在引用类型的参数上具有堆栈语义的想法与语言设计作斗争。我建议你停止。如果您真的想使用.运算符,可以尝试托管引用:void f(RefType% p),它也应该适用于接口:void f2(Base% p)。但是克隆和处理引用类型的结果并不好,对这些类型做任何有用的事情取决于你处理原始对象而不是副本。

于 2012-05-23T16:12:51.743 回答