⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 accessor.jc

📁 The JILRunOnly project is a simple command-line application written in ANSI-C that is intended to de
💻 JC
字号:
/*
 *	accessor.jc
 *
 *	This script discusses the 'accessor' keyword.
 */

import stdlib;

/*
 *	JewelScript doesn't know the 'public', 'protected' and 'private' keywords
 *	known from C++ and Java. By default, other classes or global functions have
 *	full access to any member of an object.
 *	However, JewelScript supports a quite powerful way of controlling access
 *	to member variables. Consider this example class, Foo:
 */

class Foo
{
	method Foo()
	{
		fooValue = 0;
	}

	accessor long fooValue()
	{
		return fooValue;
	}

	accessor fooValue( long f )
	{
		fooValue = f;
	}

	long fooValue;
}

/*
 *	The accessor keyword declares / defines a special kind of method and can only be
 *	use for methods that either:
 *		a) have no argument and a return value, or
 *		b) have no return value and *ONE* function argument
 *
 *	Declaring a method as an accessor will tell the compiler that this function can be
 *	used AS IF the function name was a member variable, so if we write:
 */

function test1()
{
	Foo f = new Foo();

	f.fooValue = 27;		// will call fooValue( 27 );
	long x = f.fooValue;	// will call fooValue();
}

/*
 *	It is important to understand what really happens, because when looking at the code
 *	in function test1, you would think this is a normal access to a member variable.
 *	But it is not, because class Foo defines two accessor methods which have the same name
 *	as a member variable, and thus _HIDE_ this member variable from the 'outside' of the class.
 *	From now on, everytime a method of another class or a global function assigns a value to
 *	'fooValue', the compiler will generate a call to it's accessor method.
 *	And everytime a method of another class or a global function reads a value from it, the
 *	compiler will generate a call to the other accessor method.
 *	Inside these accessor methods, we have full control over how the real fooValue variable
 *	is written or read, from simple assignment / returning the value, to checking the
 *	value against limits, to complex operations - anything can be done.
 *	Note that the compiler will use accessors as soon as you define *ONE* of the two
 *	accessor methods for a variable, that way we can make "read-only" or even "write-only"
 *	member variables:
 */

class FooB
{
	method FooB()
	{
		fooValue = 0;
	}

	accessor long fooValue()
	{
		return fooValue;
	}

	long fooValue;
}

function test2()
{
	FooB f = new FooB();

//	f.fooValue = 27;		// will fail, because accessor not defined
	long x = f.fooValue;	// will call fooValue();
}

/*
 *	It is not mandatory for accessor methods to hide a member variable with the same name.
 *	In fact, you can choose any name for an accessor method, and then use that method like
 *	you would use a variable.
 *	That way we can add 'virtual' variables to a class (virtual in terms of "exist only
 *	in thought", not in terms of inheritance); variables that are not physically present
 *	in the object:
 */

class FooC
{
	method FooC(const string& name)
	{
		fooName = name;
	}

	accessor long length()
	{
		return fooName.length;
	}

	string fooName;
}

function test3()
{
	FooC f = new FooC( "Benjamin" );

	long x = f.length;	// will call length();
}

/*
 *	The above example shows a simple class that stores a string that is passed to the object
 *	in it's constructor. Additionally it defines an accessor method that returns the length
 *	of the stored string. We can read this value as if 'length' were a member variable of FooC,
 *	but we cannot write to it.
 *	Also note that, since accessors are methods, they can be declared in interfaces, in effect
 *	allowing us to declare 'member variables' as a part of the common interface for inheriting
 *	classes:
 */

interface IPerson
{
	method			IPerson(const string&, long);

	accessor		m_Name(const string&);
	accessor string	m_Name();

	accessor		m_Age(long);
	accessor long	m_Age();
}

/*
 *	All inheriting classes of interface IPerson will have to implement accessor methods for
 *	'm_Name' and 'm_Age', which means you can safely assume any object derived from this
 *	interface has these two 'member variables' and can assign values to them, or read out
 *	their values:
 */

class SimplePerson : interface IPerson
{
	method SimplePerson(const string& name, long age)
	{
		m_Name = name;
		m_Age = age;
	}
	accessor		m_Name(const string& name)	{ m_Name = name; }
	accessor string	m_Name()					{ return m_Name; }
	accessor		m_Age(long age)				{ m_Age = age; }
	accessor long	m_Age()						{ return m_Age; }

	string	m_Name;
	long	m_Age;
}

function test4a(IPerson& aPerson)
{
	string n = aPerson.m_Name;
	long a = aPerson.m_Age;

	stdlib::Printf("Name: %s\nAge:  %d\n", {n, a});

	aPerson.m_Name = "Peter";
	aPerson.m_Age = 27;
}

function test4()
{
	SimplePerson person = new SimplePerson("Benjamin", 39);

	test4a( person );
	test4a( person );
}

/*
 *	function main
 *
 *	call'em all.
 */

function string main(const array& args)
{
	test1();
	test2();
	test3();
	test4();
	return "";
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -