我在C ++ / CLI中遇到的东西违背了我以为我所知道的东西:
通常,如果将对象传递给函数,则使用点来访问其方法(这也适用于ref
类,以及一些额外的构造函数):
value class Value {
void Print() { Console::WriteLine("Value"); }
};
void f(Value v) {
v.Print();
}
通常,通过接口将对象传递给函数会强制您在参数上放置^
,并在方法调用中使用->
:
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();
}
参数列表:
.
到目前为止,我认为直接引用对象总是使用->
,并且通过句柄引用它们总是使用->
。这似乎直接使用{{1}}引用了一个对象 - 我错了什么?
答案 0 :(得分:1)
他们试图使C ++ / CLI语法等同于C ++语法,但这并不是特别成功。规则是您使用.
访问值类型的成员,->
来访问引用类型的成员。< / p>
并发症第一是堆栈语义。您可以删除帽子以声明引用类型的局部变量。然后,编译器自动生成析构函数调用,然后自动将其放置在作用域块的末尾。尝试使托管类型的行为类似于C ++类型并拯救RAII模式。
第二个并发症是编译器允许在值类型的变量上使用hat。其中99%的类型是一个错误,特别令人讨厌,因为在运行时它非常昂贵,因为价值被装箱了。
泛型使其最终不明确,类型参数可以是值类型或引用类型。这将使具体类型为值或引用类型,直到运行时才进行排序。请注意,在您的示例中允许这样做,值类型可以实现接口。那么规则是你总是在类型参数的变量上编写没有帽子的代码,将它们视为值类型。但是使用箭头将这些变量取消引用,就好像它们是引用类型引用一样。是的,非常混乱。
答案 1 :(得分:0)
到目前为止,我认为直接引用对象总是使用
.
,并且通过句柄引用它们总是使用->
。这似乎直接使用->
引用了一个对象 - 我错了什么?
你的第一句话是完全正确的。对于你的第二句......你没有直接访问对象。 T
本身将是句柄类型,例如String^
。
使用额外的copy-ish构造函数在引用类型的参数上具有堆栈语义的想法正在与语言设计作斗争。我建议你停止。如果您确实想使用.
运算符,则可以尝试托管引用:void f(RefType% p)
,它也适用于接口:void f2(Base% p)
。但克隆和处理引用类型并不会很好,对这些类型执行任何有用的操作取决于您处理原始对象而不是副本。