Наследование и перезапись функций: кто может вызывать родительскую функцию?

Я хочу знать, кто еще может вызвать оригинальную перезаписанную функцию в случае наследования.

Предположим, у меня есть следующие настройки:

contract A{
   address public owner;

   function A(){
       owner = msg.sender;
   }

   function doSomething(){
       // does something
   }
}

contract B is A{

   function doSomething(){
       require(msg.sender == owner);
       // do something like A but restrict this function execution to owner
       super.doSomething();
   }

}

Если я разверну контракт B, может ли какая-то внешняя учетная запись, которая не является владельцем, по-прежнему вызывать doSomethingродительский контракт A? Или может какой-то вредоносный контракт выполнить следующее:

contract EvilDoer{

    function doSomethingEvil{
         A contractB = A(addressOfdeployedB);

         contractB.doSomething();
    }

}

Или перезаписанные функции защищены от внешнего использования?

РЕДАКТИРОВАТЬ: перегрузка

Возможно, мне и другим было бы интересно и полезно уточнить следующее: Что происходит в случае перегрузки функции , т.е. если сигнатура в дочернем классе отличается от родительского (например, предполагается function doSomething(uint256 someNumber){...}в контракте B)?

Ответы (1)

Сначала последний вопрос: концепция перегрузки применима к Solidity , но, что касается других языков программирования, поддерживающих функции перегрузки, то есть C++, они никак не связаны друг с другом.

Функции с одинаковым именем, но разными параметрами идентифицируются по разным сигнатурам, поэтому на самом деле это разные функции. Если ContractAопределяет doSomething(), ContractBопределяет doSomething(string myString)и ContractBнаследует от ContractA, конечный ContractB будет иметь две допустимые функции, которые пользователь может вызывать: doSomething()и doSomething(string myString). Видимость также является частью подписи, но ее нельзя перегружать.

Главный вопрос сейчас. Извне контракта вы не можете вызвать базовую функцию, которая была переопределена . Это связано с тем, что то, что вы вызываете извне, является окончательной реализацией контракта, независимо от того, как вы определяете интерфейс на клиенте для его вызова.

Если вы определяете

contract EvilDoer{
    function doSomethingEvil{
         A contractB = A(addressOfdeployedB);
         contractB.doSomething();
    }
}

Вы просто определяете другой — и более ограничительный — указатель на ContractBи на его реализацию doSomething(). И его реализация является последней.

Но эй, я знаю, что видимость функции по умолчанию общедоступна, что, если я явно определю базовую функцию ContractAкак external?

Немного, потому что вы не можете переопределить функцию, изменяющую ее расширенную сигнатуру. Параметры видимости и возврата являются частью сигнатуры расширенной функции, поэтому компилятор выдает ошибку:

TypeError: Override changes extended function signature.

Если вы хотите скомпилировать, вам нужно использовать тот же externalмодификатор и в ContractBфункции, и опять же, последняя реализация функции выигрывает в любом случае.

Обратите внимание, что изменение параметров видимости или возврата также не считается перегрузкой, поскольку функции идентифицируются сигнатурами, контракты не могут иметь две функции с одинаковой сигнатурой и разными расширенными атрибутами.

Для получения дополнительной информации о темах наследования вы можете прочитать официальную документацию , в частности информацию о superключевом слове и окончательный граф наследования контракта.