如何:定义和使用类和结构 (c++/cli)
对象化 引用(ref) 类型,并且值类型只能实在托管堆在堆栈上或在本机堆。 // mcppv2_ref_class2.cpp // compile with: /clr ref class myclass { public: int i; // nested class ref class myclass2 { public: int i; }; // nested interface interface struct myinterface { void f(); }; }; ref class myclass2 : public myclass::myinterface { public: virtual void f() { system::console::writeline("test"); } }; public value struct mystruct { void f() { system::console::writeline("test"); } }; int main() { // instantiate ref type on garbage-collected heap myclass ^ p_myclass = gcnew myclass; p_myclass -> i = 4; // instantiate value type on garbage-collected heap mystruct ^ p_mystruct = gcnew mystruct; p_mystruct -> f(); // instantiate value type on the stack mystruct p_mystruct2; p_mystruct2.f(); // instantiate nested ref type on garbage-collected heap myclass::myclass2 ^ p_myclass2 = gcnew myclass::myclass2; p_myclass2 -> i = 5; }抽象类 一个隐式抽象类 无法实例化。 选件类隐式是抽象的,如果选件类的基础是接口,并选件类不实现任何接口的成员函数。 如果无法使用从从接口派生的选件类的对象,原因可能是选件类隐式是抽象的。 有关抽象类的更多信息,请参见 摘要。 下面的代码示例演示,myclass 选件类无法实例化,因为函数 myclass::func2 未实现。 使示例生成,则取消 myclass::func2。 // mcppv2_ref_class5.cpp // compile with: /clr interface struct myinterface { void func1(); void func2(); }; ref class myclass : public myinterface { public: void func1(){} // void func2(){} }; int main() { myclass ^ h_myclass = gcnew myclass; // c2259 // to resolve, uncomment myclass::func2. }键入可见性 您可以控制公共语言运行时 (clr) 类型的可见性,以便,因此,如果程序集引用,键入程序集可以看到或不显示在程序集中。 public 指示类型可见对包含程序集的一个 #using 指令包含该类型的所有源文件。 private 指示类型不可见对包含程序集的一个 #using 指令包含该类型的源文件。 但是,专用类型位于同一个程序集中可见的。 默认情况下,选件类的可见性是 private。 默认情况下在 v**ual c++ 2005 之前,本机类型具有程序集外公共可访问性。 使 编译器警告(等级 1)c4692 帮助您发现位置不正确地使用私有本机类型。 使用 make_public 说明为公共可访问性本机类型不能修改的源代码文件。 有关更多信息,请参见 #using指令(c++)。 下面的示例演示如何声明类型并指定它们的可访问性,然后访问在程序集中的某些类型。 当然,使用 #using,因此,如果具有专用类型的程序集引用,因此,只有程序集中的公共类型才可见。 // type_v**ibility.cpp // compile with: /clr using namespace system; // public type, v**ible inside and outside assembly public ref struct public_class { void test(){console::writeline("in public_class");} }; // private type, v**ible inside but not outside assembly private ref struct private_class { void test(){console::writeline("in private_class");} }; // default accessibility ** private ref class private_class_2 { public: void test(){console::writeline("in private_class_2");} }; int main() { public_class ^ a = gcnew public_class; a->test(); private_class ^ b = gcnew private_class; b->test(); private_class_2 ^ c = gcnew private_class_2; c->test(); }output 在public_class 在 private_class_2 的 private_class 现在,我们复盖前一个示例,使其编译为 dll。 // type_v**ibility_2.cpp // compile with: /clr /ld using namespace system; // public type, v**ible inside and outside the assembly public ref struct public_class { void test(){console::writeline("in public_class");} }; // private type, v**ible inside but not outside the assembly private ref struct private_class { void test(){console::writeline("in private_class");} }; // by default, accessibility ** private ref class private_class_2 { public: void test(){console::writeline("in private_class_2");} }; 下一个示例演示如何在程序集外访问类型。 在该示例中,客户端使用上一示例中生成的组件。 // type_v**ibility_3.cpp // compile with: /clr #using "type_v**ibility_2.dll" int main() { public_class ^ a = gcnew public_class; a->test(); // private types not accessible outside the assembly // private_class ^ b = gcnew private_class; // private_class_2 ^ c = gcnew private_class_2; }output 在public_class 成员可见性 您与到它的访问从程序集外部使用对访问说明符 public、protected和private可以减少对公共选件类成员的访问从同一程序集的内部变量 下表汇总了各种访问说明符的效果: 说明符 效果public 成员可访问的内部和外部程序集。 有关更多信息,请参见 公共(c++)。 private 成员不可访问,以及在程序集外。 有关更多信息,请参见 私有(c++)。 protected 成员是可访问的于并且仅对外部程序集,但是,自派生类型。 有关更多信息,请参见 保护(c++)。 internal 成员在程序集外是公共在程序集内,但私有的。 internal 是上下文相关**。 有关更多信息,请参见 上下文相关的**(c++ 组件扩展)。 public protected -or- protected public 成员是公共在程序集内,但在程序集外保护。 private protected -or- protected private 保护成员在程序集内,但在私有程序集中。 下面的示例显示具有成员声明了不同的可访问性,然后显示访问这些成员从程序集内的公共类型。 // type_member_v**ibility.cpp // compile with: /clr using namespace system; // public type, v**ible inside and outside the assembly public ref class public_class { public: void public_function(){system::console::writeline("in public_function");} private: void private_function(){system::console::writeline("in private_function");} protected: void protected_function(){system::console::writeline("in protected_function");} internal: void internal_function(){system::console::writeline("in internal_function");} protected public: void protected_public_function(){system::console::writeline("in protected_public_function");} public protected: void public_protected_function(){system::console::writeline("in public_protected_function");} private protected: void private_protected_function(){system::console::writeline("in private_protected_function");} protected private: void protected_private_function(){system::console::writeline("in protected_private_function");} }; // a derived type, calls protected functions ref struct myclass : public public_class { void test() { console::writeline("======================="); console::writeline("in function of derived class"); protected_function(); protected_private_function(); private_protected_function(); console::writeline("exiting function of derived class"); console::writeline("======================="); } }; int main() { public_class ^ a = gcnew public_class; myclass ^ b = gcnew myclass; a->public_function(); a->protected_public_function(); a->public_protected_function(); // accessible inside but not outside the assembly a->internal_function(); // call protected functions b->test(); // not accessible inside or outside the assembly // a->private_function(); }output 在public_function 在 protected_public_function 在 internal_function ======================= 的 public_protected_function 在派生类的功能。protected_function 在 protected_private_function 在退出派生类 ======================= 的功能 private_protected_function 现在我们生成前面的示例作为 dll。 // type_member_v**ibility_2.cpp // compile with: /clr /ld using namespace system; // public type, v**ible inside and outside the assembly public ref class public_class { public: void public_function(){system::console::writeline("in public_function");} private: void private_function(){system::console::writeline("in private_function");} protected: void protected_function(){system::console::writeline("in protected_function");} internal: void internal_function(){system::console::writeline("in internal_function");} protected public: void protected_public_function(){system::console::writeline("in protected_public_function");} public protected: void public_protected_function(){system::console::writeline("in public_protected_function");} private protected: void private_protected_function(){system::console::writeline("in private_protected_function");} protected private: void protected_private_function(){system::console::writeline("in protected_private_function");} }; // a derived type, calls protected functions ref struct myclass : public public_class { void test() { console::writeline("======================="); console::writeline("in function of derived class"); protected_function(); protected_private_function(); private_protected_function(); console::writeline("exiting function of derived class"); console::writeline("======================="); } }; 下面的示例如何使用上一示例中创建的元素从而显示访问成员从程序集外部。 // type_member_v**ibility_3.cpp // compile with: /clr #using "type_member_v**ibility_2.dll" using namespace system; // a derived type, calls protected functions ref struct myclass : public public_class { void test() { console::writeline("======================="); console::writeline("in function of derived class"); protected_function(); protected_public_function(); public_protected_function(); console::writeline("exiting function of derived class"); console::writeline("======================="); } }; int main() { public_class ^ a = gcnew public_class; myclass ^ b = gcnew myclass; a->public_function(); // call protected functions b->test(); // can't be called outside the assembly // a->private_function(); // a->internal_function(); // a->protected_private_function(); // a->private_protected_function(); }output 在派生类中函数的 public_function ======================= 在 protected_function 在 protected_public_function 在退出派生类 ======================= 的功能 public_protected_function 公共和私有本机选件类 本机类型可以从托管类型引用。 例如,在托管类型的函数会采用类型是本机结构的参数。 如果托管和函数的类型是公共的程序集中,则本机类型也必须是公共的。 // mcppv2_ref_class3.h // native type public struct n { n(){} int i; }; 接下来,创建一个使用本机类型的源代码文件: // mcppv2_ref_class3.cpp // compile with: /clr /ld #include "mcppv2_ref_class3.h" // public managed type public ref struct r { // public function that takes a native type void f(n nn) {} }; 现在,请生成客户端: // mcppv2_ref_class4.cpp // compile with: /clr #using "mcppv2_ref_class3.dll" #include "mcppv2_ref_class3.h" int main() { r ^r = gcnew r; n n; r->f(n); }静态构造函数 clr 类型 (例如,选件类或结构可以具有可用于初始化静态数据成员的静态构造函数。 该类型的所有静态成员首次,访问静态构造函数调用最多一次调用和。 实例构造函数始终运行静态构造函数。 如果选件类具有静态构造函数,编译器不能内联调用构造函数。 编译器无法内联对函数的任何成员,如果选件类是值类型,具有静态构造函数和没有实例构造函数。 clr 可以内联调用,但是,编译器无法。 因为被视为由 clr,仅调用定义静态构造函数作为私有成员函数。 有关静态构造函数的更多信息,请参见 如何:定义接口静态构造函数 (c++/cli)。 // mcppv2_ref_class6.cpp // compile with: /clr using namespace system; ref class myclass { private: static int i = 0; static myclass() { console::writeline("in static constructor"); i = 9; } public: static void test() { i++; console::writeline(i); } }; int main() { myclass::test(); myclass::test(); }output 在静态构造函数 10 11 此指针的语义 当使用 v**ual c++ 定义类型时,在引用类型的 th** 指针为类型“handles”。 在值类型的 th** 指针为类型“内部指针”。 尽管默认值索引器调用时,这些 th** 指针的语义不同可能导致意外行为。 下一个示例显示正确方法访问一个默认值索引器在 ref 类型和值类型。 有关更多信息,请参见 对象句柄运算符 (^)(c++ 组件扩展) interior_ptr (c++/cli) 如何:使用索引属性// semantics_of_th**_pointer.cpp // compile with: /clr using namespace system; ref struct a { property double default[double] { double get(double data) { return data*data; } } a() { // accessing default indexer console::writeline("{0}", th**[3.3]); } }; value struct b { property double default[double] { double get(double data) { return data*data; } } void test() { // accessing default indexer console::writeline("{0}", th**->default[3.3]); } }; int main() { a ^ mya = gcnew a(); b ^ myb = gcnew b(); myb->test(); }output 10.89 10.89 隐藏由签名功能 在标准 c++ 中,在基类中的函数由具有相同名称在派生类中隐藏功能,因此,即使派生类功能具有相同数量或参数。 这称为" 按名称隐藏 语义。 在引用类型,因此,如果该名称和参数列表相同,在基类中的函数可以按功能仅隐藏在派生类。 这称为" 隐藏由签名 语义。 当其所有函数在元数据标记为 hidebysig时,选件类被视为隐藏由签名选件类。 默认情况下,创建在 /clr 下的所有选件类具有 hidebysig 功能。 但是,编译使用 /clr:oldsyntax 的选件类没有 hidebysig 功能;相反,它们是隐藏按名排序功能。 当选件类具有 hidebysig 功能时,编译器将任何不按名称隐藏功能直接基类,但是,如果编译器遇到在继承链中隐藏按名称选件类,将继续该隐藏按名排序行为。 隐藏由签名语义下,那么,当函数调用对象时,编译器确定包含一个功能可以满足函数调用的派生类。 如果只有在无法满足调用的选件类中的函数,编译器调用该函数。 如果存在多个可以满足调用的选件类中的函数,编译器使用 hyper-v 加载决策规则确定要调用的函数。 有关超加载规则的更多信息,请参见 函数重载、"。 对于特定函数调用,在基类中的函数可能具有与在派生类中的函数使其成为稍微好的匹配的签名。 但是,在中,如果函数显式调用该派生类的对象,派生类中的函数调用。 由于返回值不被视为一部分的函数的签名,一个基类功能隐藏,如果它具有相同名称和取出操作的数量和种类参数和一个派生类功能相同,因此,即使在返回值的类型不同。 下面的示例显示,在基类中的函数不受功能隐藏在派生类。 // hide_by_signature_1.cpp // compile with: /clr using namespace system; ref struct base { void test() { console::writeline("base::test"); } }; ref struct derived : public base { void test(int i) { console::writeline("derived::test"); } }; int main() { derived ^ t = gcnew derived; // test() in the base class will not be hidden t->test(); }output base::test 下面的示例演示,v**ual c++ 编译器会在派生的类选件均匀的函数,如果需要转换匹配一个或多个参数和不调用是一个更好的最为匹配的基类的一个函数调用。 // hide_by_signature_2.cpp // compile with: /clr using namespace system; ref struct base { void test2(single d) { console::writeline("base::test2"); } }; ref struct derived : public base { void test2(double f) { console::writeline("derived::test2"); } }; int main() { derived ^ t = gcnew derived; // base::test2 ** a better match, but the compiler // calls a function in the derived class if possible t->test2(3.14f); }output derived::test2 下面的示例演示,隐藏功能是可能的,即使该基类具有签名和派生类相同。 // hide_by_signature_3.cpp // compile with: /clr using namespace system; ref struct base { int test4() { console::writeline("base::test4"); return 9; } }; ref struct derived : public base { char test4() { console::writeline("derived::test4"); return 'a'; } }; int main() { derived ^ t = gcnew derived; // base::test4 ** hidden int i = t->test4(); console::writeline(i); }output derived::test4 97 下面的示例定义了使用 /clr:oldsyntax,生成的一个元素。 定义使用 c++ 托管扩展的选件类具有隐藏按名成员函数。 20210311