面向对象

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个特殊方法的名字将不能被使用。