如何创建一个子类,该子类采用相同函数名的不同参数?

发布于 2024-12-13 06:46:28 字数 1253 浏览 1 评论 0原文

所以我制作了这个简单的界面:

package{
    public interface GraphADT{
        function addNode(newNode:Node):Boolean;     
    }
}

我还创建了一个简单的类 Graph:

package{

    public class Graph implements GraphADT{

        protected var nodes:LinkedList;

        public function Graph(){
            nodes = new LinkedList();
        }

        public function addNode (newNode:Node):Boolean{
            return nodes.add(newNode);
        }
}

最后但并非最不重要的一点是我创建了另一个简单的类 AdjacancyListGraph:

package{
    public class AdjacancyListGraph extends Graph{

        public function AdjacancyListGraph(){
            super();
        }

        override public function addNode(newNode:AwareNode):Boolean{
            return nodes.add(newNode);
        }
}

在这里进行此设置会给我带来错误,即:

1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.

经过仔细检查,很明显 AS3 没有不喜欢来自 Graph 的不同 Graph 类 newNode:Node 和 AdjacancyListGraph 的 newNode:AwareNode 的不同参数类型

但是我不明白为什么这会成为问题,因为AwareNodeNode 的子类。

有什么方法可以让我的代码正常工作,同时保持代码的完整性?

So I have made this simple interface:

package{
    public interface GraphADT{
        function addNode(newNode:Node):Boolean;     
    }
}

I have also created a simple class Graph:

package{

    public class Graph implements GraphADT{

        protected var nodes:LinkedList;

        public function Graph(){
            nodes = new LinkedList();
        }

        public function addNode (newNode:Node):Boolean{
            return nodes.add(newNode);
        }
}

last but not least I have created another simple class AdjacancyListGraph:

package{
    public class AdjacancyListGraph extends Graph{

        public function AdjacancyListGraph(){
            super();
        }

        override public function addNode(newNode:AwareNode):Boolean{
            return nodes.add(newNode);
        }
}

Having this setup here is giving me errors, namely:

1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.

Upon closer inspection it was apparent that AS3 doesn't like the different parameter types from the different Graph classes newNode:Node from Graph , and newNode:AwareNode from AdjacancyListGraph

However I don't understand why that would be a problem since AwareNode is a subClass of Node.

Is there any way I can make my code work, while keeping the integrity of the code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼趣 2024-12-20 06:46:28

简单答案

如果您确实不需要“addNode()”函数只接受 AwareNode,您可以将参数类型更改为 Node。由于 AwareNode 扩展了 Node,因此您可以毫无问题地传入 AwareNode。您可以检查函数体内的类型正确性:

subclass... {
    override public function addNode (node:Node ) : Boolean {
        if (node is AwareNode) return nodes.add(node);
        return false;
    }
}

更长的答案

我同意@32bitkid的观点,即您收到错误,因为接口中为 addNode() 定义的参数类型与中的类型不同你的子类。

然而,当前的主要问题是 ActionScript 通常不允许函数重载(具有多个同名方法,但具有不同的参数或返回值),因为每个函数都被视为通用类成员 - 同样的方式一个变量是。您可以这样调用函数:

myClass.addNode (node);

但您也可以这样调用它:

myClass["addNode"](node);

每个成员都按名称存储 - 并且您始终可以使用该名称来访问它。不幸的是,这意味着您只能在类中使用每个函数名称一次,无论它需要多少个类型的参数 - 任何事情都是有代价的:您在一方面获得了灵活性,但在另一方面却失去了一些舒适感。

因此,只允许您重写具有完全相同签名的方法 - 这是一种让您坚持编写基类时所决定的方法。虽然您显然可能会认为这是一个坏主意,并且使用重载或在子类中允许不同的签名更有意义,但 AS 处理函数的方式有一些优点,这最终将帮助您解决问题:可以使用类型检查函数,甚至可以将其作为参数传递!

考虑一下:

class... {

    protected function check (node:Node) : Boolean {
        return node is Node;
    }    

    public function addNode (node:Node) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}

在这个例子中,您可以重写 check (node:Node):

subclass... {
    override protected function check (node:Node) : Boolean {
        return node is AwareNode;
    } 
}

并达到您想要的完全相同的效果,而不会破坏接口契约 - 除非在您的示例中,如果您传入了错误的参数,编译器将抛出错误类型,而在这个例子中,错误仅在运行时可见(false 返回值)。

您还可以使其更加动态:

class... {
    public function addNode (node:Node, check : Function ) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}

请注意,此 addNode 函数接受 Function 作为参数,并且我们调用该函数而不是类方法:

var f:Function = function (node:Node) : Boolean {
    return node is AwareNode;
}

addNode (node, f);

这将使您的实现变得非常灵活 - 您甚至可以做到合理性检查匿名函数,例如验证节点的内容。而且您甚至不必扩展您的类,除非您要添加除类型正确性之外的其他功能。

拥有一个接口还允许您创建不继承原始基类的实现 - 您可以编写一个完全不同的类层次结构,它只需要实现该接口,并且您以前的所有代码都将保持有效。

Simple answer:

If you don't really, really need your 'addNode()' function to accept only an AwareNode, you can just change the parameter type to Node. Since AwareNode extends Node, you can pass in an AwareNode without problems. You could check for type correctness within the function body :

subclass... {
    override public function addNode (node:Node ) : Boolean {
        if (node is AwareNode) return nodes.add(node);
        return false;
    }
}

Longer answer:

I agree with @32bitkid that your are getting an error, because the parameter type defined for addNode() in your interface differs from the type in your subclass.

However, the main problem at hand is that ActionScript generally does not allow function overloading (having more than one method of the same name, but with different parameters or return values), because each function is treated like a generic class member - the same way a variable is. You might call a function like this:

myClass.addNode (node);

but you might also call it like this:

myClass["addNode"](node);

Each member is stored by name - and you can always use that name to access it. Unfortunately, this means that you are only allowed to use each function name once within a class, regardless of how many parameters of which type it takes - nothing comes without a price: You gain flexibility in one regard, you lose some comfort in another.

Hence, you are only allowed to override methods with the exact same signature - it's a way to make you stick to what you decided upon when you wrote the base class. While you could obviously argue that this is a bad idea, and that it makes more sense to use overloading or allow different signatures in subclasses, there are some advantages to the way that AS handles functions, which will eventually help you solve your problem: You can use a type-checking function, or even pass one on as a parameter!

Consider this:

class... {

    protected function check (node:Node) : Boolean {
        return node is Node;
    }    

    public function addNode (node:Node) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}

In this example, you could override check (node:Node):

subclass... {
    override protected function check (node:Node) : Boolean {
        return node is AwareNode;
    } 
}

and achieve the exact same effect you desired, without breaking the interface contract - except, in your example, the compiler would throw an error if you passed in the wrong type, while in this one, the mistake would only be visible at runtime (a false return value).

You can also make this even more dynamic:

class... {
    public function addNode (node:Node, check : Function ) : Boolean {
        if (check(node)) return nodes.add(node);
        return false;
    }
}

Note that this addNode function accepts a Function as a parameter, and that we call that function instead of a class method:

var f:Function = function (node:Node) : Boolean {
    return node is AwareNode;
}

addNode (node, f);

This would allow you to become very flexible with your implementation - you can even do plausibility checks in the anonymous function, such as verifying the node's content. And you wouldn't even have to extend your class, unless you were going to add other functionality than just type correctness.

Having an interface will also allow you to create implementations that don't inherit from the original base class - you can write a whole different class hierarchy, it only has to implement the interface, and all your previous code will remain valid.

似狗非友 2024-12-20 06:46:28

我想问题实际上是这样的:你想实现什么目标?

至于为什么会出现错误,请考虑以下几点:

public class AnotherNode extends Node { }

然后:

var alGraph:AdjacancyListGraph = new AdjacancyListGraph();

alGraph.addNode(new AnotherNode());  
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)

// but what about the contract? 

var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?

根据界面,这应该没问题。但你的实现却说不然,你的实现说它只接受 AwareNode。存在明显的不匹配。如果你想要一个接口,一个你的对象应该遵循的契约,那么你不妨遵循它。否则,界面的意义何在?

如果你想这样做,我认为架构在某个地方搞砸了。即使语言支持它,我也会说这是一个“坏主意™”

I guess the question is really this: What are you trying to accomplish?

As to why you are getting an error, consider this:

public class AnotherNode extends Node { }

and then:

var alGraph:AdjacancyListGraph = new AdjacancyListGraph();

alGraph.addNode(new AnotherNode());  
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)

// but what about the contract? 

var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?

According to the interface this should be fine. But your implemenation says otherwise, your implemenation says that it will only accept a AwareNode. There is an obvious mismatch. If you are going to have an interface, a contract that your object should follow, then you might as well follow it. Otherwise, whats the point of the interface in the first place.

I submit that architecture messed up somewhere if you are trying to do this. Even if the language were to support it, I would say that its a "Bad Idea™"

说不完的你爱 2024-12-20 06:46:28

有一种更简单的方法,然后是上面建议的,但不太安全:

public class Parent {
public function get foo():Function { return this._foo; }
protected var _foo:Function = function(node:Node):void { ... }}

public class Child extends Parent {
public function Child() {
super();
this._foo = function(node:AnotherNode):void { ... }}}

当然 _foo 不需要就地声明,所使用的语法仅用于简短和演示目的。
您将失去编译器检查类型的能力,但运行时类型匹配仍然适用。

还有另一种方法 - 不要在它们专门的类中声明方法,而是将它们设为静态,这样您就不会自动继承它们:

public class Parent {
public static function foo(parent:Parent, node:Node):Function { ... }}

public class Child extends Parent {
public static function foo(parent:Child, node:Node):Function { ... }}

请注意,在第二种情况下,受保护的字段可以在静态方法内部访问,因此您可以达到一定的封装性。此外,如果您有很多父实例或子实例,您将节省单个实例的内存占用(作为静态方法,因此静态方法只存在它们的一份副本,但将为每个实例复制实例方法)。缺点是你将无法使用界面(实际上可以是一种改进......取决于你的个人喜好)。

There's an easier way, then suggested above, but less safe:

public class Parent {
public function get foo():Function { return this._foo; }
protected var _foo:Function = function(node:Node):void { ... }}

public class Child extends Parent {
public function Child() {
super();
this._foo = function(node:AnotherNode):void { ... }}}

Of course _foo needs not be declared in place, the syntax used is for shortness and demonstration purposes only.
You will loose the ability of the compiler to check types, but the runtime type matching will still apply.

Yet another way to go about it - don't declare methods in the classes they specialize on, rather make them static, then you will not inherit them automatically:

public class Parent {
public static function foo(parent:Parent, node:Node):Function { ... }}

public class Child extends Parent {
public static function foo(parent:Child, node:Node):Function { ... }}

Note that in second case protected fields are accessible inside the static method, so you can achieve certain encapsulation. Besides, if you have a lot of Parent or Child instances, you will save on individual instance memory footprint (as static methods therefore static there exists only one copy of them, but instance methods would be copied for each instance). The disadvantage is that you won't be able to use interfaces (can be actually an improvement... depends on your personal preferences).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文