Я хочу знать, кто еще может вызвать оригинальную перезаписанную функцию в случае наследования.
Предположим, у меня есть следующие настройки:
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
)?
Сначала последний вопрос: концепция перегрузки применима к 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
ключевом слове и окончательный граф наследования контракта.