面向对象
Silk支持面向对象程序设计,类是面向对象的核心,通常被称为用户定义的类型,用来描述具有相同的属性和方法的对象的集合,它包含了数据(属性)和用于处理数据的函数(方法)。
类的定义
类的定义以关键字class开头,有如下的形式:
class class_name( parameter )
{
init;
functions;
}
class:关键字class,类的定义以class开头
class_name:类名字,类的名字必须唯一,不能与其它类,函数,变量,和关键字重名。
parameter:参数,传递给类用以初始化的参数列表,参数是可选的,可以是一个参数,也可以是一组参数,也可以没有参数。
init:初始化类的各种属性(成员变量),创建一个类对象时,会初始化这个对象的属性。
functions:类的各种方法,也就是处理类属性的函数,和普通函数一样定义,以func开头。
类的对象
类定义以后,需要通过创建类的对象来使用,创建类的对象就像调用函数一样,返回的是类的实例化对象,通过obj.name的语法形式可以访问对象的属性和方法。
下面是一个类使用的例子:
class myClass(a,b)
{
//初始化类的属性,类内部对属性的使用必须通过隐含的self关键字
self.a=a;
self.b=b;
self.c=0;
if(a>b)
self.c=1;
//定义类的方法(函数)
func test()
{
printf("a=%d, b=%d, c=%d\n",self.a,self.b,self.c);
}
func test2()
{
self.a++;
self.test();
}
}
main()
{
obj=myClass(100,200);
obj.test2();
obj.a=300;
print(obj.a);
}
self的含义类内部对属性和方法的使用必须通过隐含的self关键字,self代表类的实例,也就是对象的本身。
类的方法与普通的函数只有一个区别——它的第一个参数是隐含的,名字就是self,代表类对象自己。
上面类的方法test相当于下面的函数,只是self被Silk自动隐藏了起来,所以在调用时不必传入。
func test(self)
{
printf("a=%d,b=%d\n",self.a,self.b);
}
类的封装类的属性和方法可以提供给类的实例对象任意调用,但某些属性和方法我们不想公开在类的外部被调用,这时可以通过定义私有属性和方法防止在外部被调用。
定义私有属性和方法很简单,类似python,以双下划线开头命名即为私有属性或方法。
class myClass(a)
{
self.__a=a;//私有属性
func __test()//私有方法
{
printf("a=%d\n",self.__a);
}
func test2()
{
self.__a++;
self.__test();
}
}
main()
{
obj=myClass(100);
obj.test2();
print(obj.__a);//无法直接调用私有属性,运行后会有错误提示
}
类的继承面向对象编程的一大优点就是可以通过继承达到代码的重用。通过继承而创建的新类称为子类或派生类,被继承的类称为父类或基类。
子类继承了父类中所有的属性和方法,可以任意调用。Silk暂时不支持多重继承。
Silk类的继承通过在类初始化的开始处实例化父类并赋值给self达成:
//父类Animal
class Animal(name)
{
self.name=name;
func description()
{
printf("this is %s\n",self.name);
}
}
//子类Dog
class Dog(name)
{
self=Animal(name);//继承父类Animal
func SetName(name)
{
self.name=name;//调用并修改父类中定义的属性
}
}
main()
{
dog=Dog("dog");
dog.description();//调用父类中的方法
dog.SetName("pet");//子类中定义的方法
dog.description();
}
运行结果:
this is dog
this is pet
方法重写如果父类中的方法的功能不能满足需求,可以在子类中重写父类的方法:
//父类Animal
class Animal(name)
{
self.name=name;
func description()
{
printf("this is %s\n",self.name);
}
}
//子类Dog
class Dog(name)
{
self=Animal(name);//继承父类Animal
func description()//重写父类中的方法
{
printf("I am %s, I can swim\n",self.name);
}
}
main()
{
dog=Dog("dog");
dog.description();
}
运行结果:
I am dog, I can swim
如果需要调用父类中被覆盖的方法,可以在重写之前保存父类的方法,在需要的地方调用:
//父类Animal
class Animal(name)
{
self.name=name;
func description()
{
printf("this is %s\n",self.name);
}
}
//子类Dog
class Dog(name)
{
self=Animal(name);//继承父类Animal
self.super_description=self.description;//保存父类的方法
func SetName(name)
{
self.name=name;//调用并修改父类中定义的属性
}
func description()//重写父类中的方法
{
self.super_description();//调用保存的父类中的方法
printf("I can swim\n");
}
}
main()
{
dog=Dog("dog");
dog.description();
}
运行结果:
this is dog
I can swim
多态多态即多种形态,多态意味着在调用对象的方法时,会根据对象的类型来执行不同的方法。
Silk是动态类型的语言,不需要指定类型,所以天生支持多态:
//父类Animal
class Animal(name)
{
self.name=name;
func description()
{
printf("this is %s\n",self.name);
}
}
//子类Dog
class Dog(name)
{
self=Animal(name);
func description()
{
printf("I am dog, I can swim\n");
}
}
//子类Bird
class Bird(name)
{
self=Animal(name);
func description()
{
printf("I am bird, I can fly\n");
}
}
func test_animal(animal)
{
//这里会根据animal的具体类型执行各自的description方法
animal.description();
}
main()
{
dog=Dog("dog");
bird=Bird("bird");
test_animal(dog);
test_animal(bird);
}
运行结果:
I am dog, I can swim
I am bird, I can fly
特殊方法类有2个内置的特殊方法
_getptr()和
_restore(ptr)用以解决对象的循环引用问题,具体请参考
内存管理。
在定义类的方法时,这2个特殊方法的名字将不能被使用。