虚函数
重写(overriding)虚函数有两种方式:隐式,显式
隐式
语法:virtual void Speak () override{};
阻止虚函数链:防止虚方法繁殖给他的后代。通常没有必要,不过可以这么做。语法:void Speak() new();也可以隐藏以后再开始一个新的虚方法 语法:virtual void Speak() new{};作者认为这两种都违反面向对象的程序设计原则。注意:纯虚函数不能被用hide。
显式(命名的(名字可以相同,也可以不同))
语法:virtual void Yip () = Dog::Speak{};
它的一个好处是可以克服new的阻止,因为他可以override不仅仅是父类,而且可以是爷爷类,甚至是祖...爷爷类,多远都行。
语法:/*begin==================
ref class Tiger : public Cat
{
public:
virtual void Growl () = Animal::Speak//注意:Grow!=speak
{}
};
END=========*/
另一个更cool的好处是:从一个虚方法产生两个不同的虚方法序列。做法是:用同一个名字开始一个新虚序列(该虚序列已经被new封了),解释这个比较让人难懂。/*翻译就更难了*/ 代码却能很好的表述:
/*begin==================
ref class Animal
{
public:
virtual void Speak ()
{
Console::WriteLine("Animal is Mysteriously Silent");
}}
ref class Cat : public Animal
{
public:
virtual void Speak() new // 虚序列被阻止了(译者:包括cat自身)
{
Console::WriteLine("Cat says Meow");
}};
ref class Tiger : public Cat
{
public:
virtual void Speak() override = Animal::Speak //注意这里
{
Console::WriteLine("Tiger says Growl");
}};
END=========*/
函数重写
函数重载
不支持缺省参数,解决方法:参数要少,在函数内初始化。//不过这好像没解决根本问题
作者希望微软能恢复缺省参数,虽然他肯定微软取消缺省参数是有原因的。
操作符重载:c++/CLI必须是静态的,因此没有了隐含的this,因此也就多了一个参数。
另外要注意,c++的操作符重载也是被c++/CLI支持的(不过就不能支持多编程语言了)。另外在同一个ref类中不同对同一个操作符即用C++也用C++/CLI。
C++/CLI中不能被重载的一些重要操作符:[],(),gcnew,new,delete
//p114重载++的例子很好
//p116注意:同时实现了x++和++x
//p117注意:〉同时实现了 (class,int)和(int,class)
属性成员
主要是解决成员变量的访问问题,在或得get set的同时,简化了访问的形式,就象普通成员变量一样访问。(c++中用getset需要显式调用getset。)
trivial属性:语法property type PropertyName;//没有太大意义
Scalar属性:语法
property type PropertyName
{
type get() {};
void set (type value) {};
}
注:只有get就是只读属性,只有set就是只写属性,getset都有是可读写属性。
属性名不能和相应的成员变量名相同;但作者推荐(并非语法强制)成员变量第一个字符小写,属性名第一个字符大写。
set中通常检查传入的变量是否符合要求,并设置相应的成员变量。
属性的使用和普通成员变量相同。
静态属性:和静态成员变量相关联。
数组属性
语法:属性的类型为array类型
用法:用[]来访问
indexed属性
用法:用[]来访问,不过[]里面可以是任何类型(数组属性只能是0,1,2,3)。
语法:
property type PropertyName [ indexType1, ..., indexTypeN ]
{
type get(indexType1 index1, ..., indexTypeN indexN) {};
void set(indexType1 index1, ..., indexTypeN indexN, type value) {};
}
关键是getset里的实现://用到了集合类,也可以自己设计(如链表)。见例子3-12
缺省indexed属性
用法:用default代替属性名,可以直接用对象名[]访问而不用加属性名(本身也没有名字(如果说有也是default))。
对应内部一个集合类成员。
Number number;
number[1]
语法:property type default [type]{}
//总结:每种属性都应由一个对应的成员。
嵌套类:
//书中有一个图清楚地表明了嵌套类的访问权限。好图啊,一图顶万言。
类型转换
static_cast
static_cast最快也最危险//not verified也就是unsafe
dynamic_cast失败,返回nullptr
safe_cast,失败,抛出异常
//const_cast呢
抽象类
抽象类的构造函数:只能放在派生类的初始化列表中;应该protected(因为它必须被继承使用)。
必须有纯虚函数,abstract不必须(单更清楚,建议加上,尤其代码很多时)
因为它必须被继承使用,所以不能sealed,但可以实现一个虚方法并sealed它//virtual void Method1() override sealed。前面讲虚方法时并没有介绍sealed。
语法:ref class AbstractExClass abstract{}
接口
语法:interface class Interfacename
interface内部只能为public,函数不用virtual,=0。
接口内可以定义属性,但不能有实现。
一个类可以同时继承一个类和多个接口,例如:ref class DerivedClass : public Base, public Interface1, public Interface2{}
另外:实现接口的方法时必须加上virtual,否则编译错误。
总结:
<skip>