PDA

Просмотр полной версии : Отсутствие доступа к защищённому свойству суперкласса


dump13
15.10.2011, 21:09
Здравствуйте,
непонятная проблема с защищённым свойством. Есть два класса: ColorMatrix и его наследник ColorMatrixInterpolator. У родительского ColorMatrix есть protected-свойство _data:

public class ColorMatrix {
protected var _isDirty:Boolean;
protected var _doConstrain:Boolean;
protected var _data:Array;
// ...
}

Наследник ColorMatrixInterpolator в конструкторе делает так:
public function ColorMatrixInterpolator (matrix0:ColorMatrix, matrix1:ColorMatrix, indices:Vector.<int> = null) {
_m0 = matrix0;
_m1 = matrix1;
_indices = indices? copyIndices (indices) : new Vector.<int> ();
_t = 0;
super (matrix0._data, false);
}
где _m0 - экземпляр ColorMatrix. Пробую компилировать - кидается исключение
Attempted access of inaccessible property _data through a reference with static type gamma.helpers:ColorMatrix.
Делаю _data пабликом - всё работает.
Подумал, может дело в SDK или FlashDevelop - юзаю последние релизные версии. Или всё-таки моя ошибка?
Если не лень, посмотрите плиз во вложениях.

goodguy
15.10.2011, 21:12
matrix0._data
Если свойство протектед, то оно доступно только потомкам класса и самому экземпляру класса.
Так что нужно вызывать его либо:
this._data либо просто _data
А в данном случае не удивительно, что нет доступа к защищенному свойству другого экземпляра. Все логично. Тут уж только паблик.

dump13
15.10.2011, 21:21
Сорри, я забыл написать, что
public class ColorMatrixInterpolator extends ColorMatrix {/*...*/}
вернее, я написал это
два класса: ColorMatrix и его наследник ColorMatrixInterpolator
но в глаза не бросается :)
В общем, совсем непонятно, что за хрень. Не попробуете скомпилировать пример у себя?

Bgg
15.10.2011, 21:26
Подумал, может дело в SDK или FlashDevelop - юзаю последние релизные версии.

Полезнее думать после чтения справки: Атрибуты свойств классов (http://help.adobe.com/ru_RU/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f32.html)

matrix0._data

Вы обращаетесь к свойству, которое закрыто для внешнего использования.

goodguy
15.10.2011, 21:32
Сорри, я забыл написать, что
Я это понял.
Свойство _data будет доступно самому экземпляру.
Но в данном случае matrix0 - это уже другой экземпляр, пусть даже того же класса.
У других экземпляров будет доступ только к его public свойствам

dump13
15.10.2011, 21:36
Ну хорошо, давайте так, я приведу здесь оба этих класса, чтобы всем было видно, что второй класс унаследован от первого.

package gamma.helpers {
import flash.filters.ColorMatrixFilter;
/**
* Матрица, используемая при создании фильтра ColorMatrixFilter.
* @author dump13
*/
public class ColorMatrix {
protected var _isDirty:Boolean;
protected var _doConstrain:Boolean;
protected var _data:Array;

public function ColorMatrix (data:Array = null, doConstrain:Boolean = false) {
if (data) {
_data = copyData (data);
_isDirty = true;
}
else {
reset ();
}
_doConstrain = doConstrain;
}

public function clone ():ColorMatrix {
return new ColorMatrix (_data, _doConstrain);
}

private function copyData (array:Array):Array {
var res:Array = [];
var na:int = array.length;
for (var n:int = 0; n < na; n++) {
res.push (array[n]);
}
return res;
}

public function reset ():void {
_data = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0];
_isDirty = true;
}

// ************************* SET METHODS **************************

/// Устанавливает "сырые" значения матрицы.
public function setRawData (array:Array):void {
if (array.length != 20) {
throw new Error ("Неверная длина массива (должна быть равна 20).");
}
_data = copyData (array);
_isDirty = true;
}

/// Устанавливает оффсет-значения (смещения) для четырёх каналов.
public function setOffsets (red:int = 0, green:int = 0, blue:int = 0, alpha:int = 0):void {
_data[4] = red;
_data[9] = green;
_data[14] = blue;
_data[19] = alpha;
_isDirty = true;
}

/// Устанавливает цветовой баланс - множители главной диагонали матрицы для четырёх каналов.
public function setBalance (red:Number = 1, green:Number = 1, blue:Number = 1, alpha:Number = 1):void {
_data[0] = red;
_data[6] = green;
_data[12] = blue;
_data[18] = alpha;
_isDirty = true;
}

/// Устанавливает смещения цветовых каналов (R, G, B) в значение offset.
public function setRGBOffset (offset:int):void {
_data[4] = offset;
_data[9] = offset;
_data[14] = offset;
_isDirty = true;
}

/// Устанавливает множители для цветовых каналов (R, G, B) в значение mult.
public function setRGBMult (mult:Number):void {
_data[0] = mult;
_data[6] = mult;
_data[12] = mult;
_isDirty = true;
}

// ************************* CONCAT METHODS ******************************

/// Прибавляет указанные оффсет-значения (смещения) к соответствующим значениям четырёх каналов.
public function addOffsets (red:int = 0, green:int = 0, blue:int = 0, alpha:int = 0):void {
_data[4] += red;
_data[9] += green;
_data[14] += blue;
_data[19] += alpha;
_isDirty = true;
}

/// Объединяет переданный цветовой баланс с текущим - умножает значения главной диагонали четырёх каналов на указанные величины.
public function concatBalance (red:Number = 1, green:Number = 1, blue:Number = 1, alpha:Number = 1):void {
_data[0] *= red;
_data[6] *= green;
_data[12] *= blue;
_data[18] *= alpha;
_isDirty = true;
}

/// Прибавляет указанные значение offset к смещениям цветовых каналов (R, G, B).
public function addRGBOffset (offset:int):void {
_data[4] += offset;
_data[9] += offset;
_data[14] += offset;
_isDirty = true;
}

// *********************** OTHER METHODS **************************

/// Создаёт и возвращает новый ColorMatrixFilter, основанный на состоянии текущей матрицы ColorMatrix. Флаг isDirty сбрасывается в false.
public function getFilter ():ColorMatrixFilter {
if (_isDirty) {
_isDirty = false;
if (_doConstrain) constrainAll ();
}
return new ColorMatrixFilter (_data);
}

/// Ограничивает смещения четырёх каналов границами [-255, 255].
public function constrainAll ():void {
constrainOffset (4);
constrainOffset (9);
constrainOffset (14);
constrainOffset (19);
_isDirty = true;
}

/// Ограничивает значение смещения канала границами [-255, 255].
/// @param index Индекс канала. Допустимые значения: 4, 9, 14, 19.
private function constrainOffset (index:int):void {
var curval:int = _data[index];
if (curval < -255) {
_data[index] = -255;
return;
}
if (curval > 255) _data[index] = 255;
}

// ACCESSORS

/// Была ли текущая матрица изменена. Сбрасывается в false каждый раз при вызове getFilter().
public function get isDirty ():Boolean { return _isDirty; }

/// Следует ли ограничивать оффсет-значения (смещения) при генерации фильтра. Значение по умолчанию - false.
public function get doConstrain ():Boolean { return _doConstrain; }
public function set doConstrain (value:Boolean):void {
_doConstrain = value;
}

}

}

А теперь второй класс. Это - наследник первого класса.

package gamma.helpers {
import flash.filters.ColorMatrixFilter;
/**
* Интерполятор содержит ссылки на две матрицы - _m0 и _m1. В векторе _indices содержатся индексы тех значений, которые необходимо интерполировать (предполагается, что значения с другими индексами в обеих матрицах совпадают). При изменении параметра t интерполятор помечается как неактуальный (_isDirty = true). При вызове getFilter() неактуальный интерполятор производит обновление своих значений, а затем уже возвращает фильтр.
* @author dump13
*/
public class ColorMatrixInterpolator extends ColorMatrix {
protected var _m0:ColorMatrix;
protected var _m1:ColorMatrix;
protected var _indices:Vector.<int>;
protected var _t:Number;

/// Конструктор интерполятора цветовых матриц. Интерполятор устанавливает свои "сырые" значения в значения матрицы matrix0.
/// @param matrix0 Первая матрица, соответствующая начальному состоянию интерполятора.
/// @param matrix1 Вторая матрица, соответствующая конечному состоянию интерполятора.
/// @param indices Вектор индексов тех значений, которые будут изменяться в процессе интерполяции. Все остальные значения будут оставаться равными соответствующим значениям из матрицы matrix0.
public function ColorMatrixInterpolator (matrix0:ColorMatrix, matrix1:ColorMatrix, indices:Vector.<int> = null) {
//super ();
_m0 = matrix0;
_m1 = matrix1;
_indices = indices? copyIndices (indices) : new Vector.<int> ();
_t = 0;
super (matrix0._data, false);
}

override public function clone ():ColorMatrix {
var ip:ColorMatrixInterpolator = new ColorMatrixInterpolator (_m0, _m1, _indices);
ip._t = _t;
return ColorMatrix (ip);
}

private function copyIndices (vec:Vector.<int>):Vector.<int> {
var res:Vector.<int> = new Vector.<int> ();
var na:int = vec.length;
for (var n:int = 0; n < na; n++) {
res.push (vec[n]);
}
return res;
}

override public function getFilter ():ColorMatrixFilter {
if (_isDirty) {
_isDirty = false;
interpolate ();
}
return new ColorMatrixFilter (_data);
}

/// Обновляет состояние интерполятора.
private function interpolate ():void {
var na:int = _indices.length;
for (var n:int = 0; n < na; n++) {
var index:int = _indices[n];
_data[index] = GMath.interpolateLinear (_m0._data[index], _m1._data[index], _t);
}
}

// ********************** INDICES SETTING **************************
// Методы из этого раздела не проверяют наличие других добавленных индексов, т.е. если добавить один и тот же индекс в вектор indices несколько раз, интерполяция также будет осуществляться повторно.

/// Заставляет интерполировать все значения матрицы.
public function setAllIndices ():void { for (var n:int = 0; n < 19; n++) { _indices.push (n); } }

/// Заставляет интерполировать множители цветовых каналов (на главной диагонали).
public function addRGBMultIndices ():void { _indices.push (0, 6, 12); }

/// Заставляет интерполировать множители, лежащие на диагонали.
public function addRGBAMultIndices ():void { _indices.push (0, 6, 12, 18); }

/// Заставляет интерполировать смещения цветовых каналов.
public function addRGBOffsetIndices ():void { _indices.push (4, 9, 14); }

/// Заставляет интерполировать смещения всех каналов.
public function addRGBAOffsetIndices ():void { _indices.push (4, 9, 14, 19); }

// ACCESSORS

/// Матрица, соответствующая начальному состоянию интерполятора. Аксессоры производят её клонирование.
public function get matrix0 ():ColorMatrix { return _m0.clone (); }
public function set matrix0 (value:ColorMatrix):void {
_m0 = value.clone ();
_isDirty = true;
}

/// Матрица, соответствующая конечному состоянию интерполятора. Аксессоры производят её клонирование.
public function get matrix1 ():ColorMatrix { return _m1.clone (); }
public function set matrix1 (value:ColorMatrix):void {
_m1 = value.clone ();
_isDirty = true;
}

/// Индексы значений, которые будут изменяться в процессе интерполяции.
public function get indices ():Vector.<int> { return _indices; }
public function set indices (value:Vector.<int>):void {
_indices = copyIndices (value);
}

/// Параметр, по которому производится интерполяция (от нуля до единицы).
public function get t ():Number { return _t; }
public function set t (value:Number):void {
_t = value;
_isDirty = true;
}

override public function set doConstrain (value:Boolean):void {
throw new Error ("Запрещено изменять doConstrain интерполятора.");
}

}

}

А теперь объясните плиз, почему свойство с атрибутом protected, который, как написано по ссылке выше,
Видимый для ссылок в том же классе и в производных классах
не видно в производном классе?

dump13
15.10.2011, 21:40
Хм... Ну вот, пока писал, человек мне уже доступно объяснил :)
Всё, вопросов нет, спасибо.

in4core
15.10.2011, 21:40
Вам уже все обяъяснили зрите в корень : protected var _m0:ColorMatrix; Это значит вы создли переменную типа protected и хотите у этой переменной схавать super (matrix0._data свойство дата которое тоже протектед. На глаз это сразу не видно но если подумать....
Вот пример того что вы делаете
class A
protected var b:int = 55;

var a:A = new A();
trace(a.b) // WTF ?

wvxvw
16.10.2011, 11:47
Вместо того, чтобы заигрывать с суперконструктором, лучше написать статический метод-фабрику, в нем, кстати, и protected свойства доступны будут.

dump13
16.10.2011, 12:55
Блин, я совсем запутался. Из этого примера просто стало понятно, что вот в таком случае протектед использовать не получится, а почему этого делать нельзя - непонятно. Помогите разобраться, например здесь доступ к _ownVar другого экземпляра работает и я всегда этим пользовался:
package gamma.tests {

public class A {
protected var _ownVar:int;

public function A (ownVar:int) {
_ownVar = ownVar;
}

public function equals (a:A):Boolean {
return _ownVar == a._ownVar;
}

}

}
То есть a в методе equals() - это уже другой экземпляр, но того же класса. Когда я в первый раз это проверил, я решил, что, раз уж _ownVar может быть доступно в каком-нибудь подклассе, то тот подкласс сможет таким же образом рыться в других экземплярах. А сейчас не могу понять, почему не может.

написать статический метод-фабрику, в нем, кстати, и protected свойства доступны будут
можно ссылку или пример?

Upd: wvxvw, всё, понял о чём речь.