Objective-C中重载的仿真方法

Objective-C中重载的仿真方法,objective-c,overloading,Objective C,Overloading,我正在用Objective-C编写一个数学库(为了好玩),现在我需要一些方法来模拟C++风格的函数重载 我想要的样子: NSNumber *x = @(25); CMVector *v = [CMVector vectorWithElements:@12, @14, @18, nil]; CMMatrix *m = [CMMatrix matrixWithRows:@[@12, @13, @0 ], @[@24, @2

我正在用Objective-C编写一个数学库(为了好玩),现在我需要一些方法来模拟C++风格的函数重载

我想要的样子:

NSNumber *x = @(25);
CMVector *v = [CMVector vectorWithElements:@12, @14, @18, nil];
CMMatrix *m = [CMMatrix matrixWithRows:@[@12, @13, @0 ],
                                       @[@24, @26, @30],
                                       @[@0,  @0,  @1 ], nil];
CMMatrix *i = [CMMatrix identityMatrixWithRank:3];

NSLog(@"%@ %@ %@ %@", [x multiply:v], [x multiply:m], [m multiply: i], [v multiply:x]);
有没有办法实现这一点

下面是我提出的一种可能的方法,使用类来表示重载函数,并将参数名称编码为类方法名称,如:

@interface CMMultiply : NSProxy

+ (NSNumber *)NSNumber:(NSNumber *)left NSNumber:(NSNumber *)right;
+ (CMVector *)NSNumber:(NSNumber *)left CMVector:(CMVector *)right;
+ (CMVector *)CMVector:(CMVector *)left NSNumber:(NSNumber *)right;
+ (CMVector *)CMVector:(CMVector *)left CMVector:(CMVector *)right;
+ (CMMatrix *)NSNumber:(NSNumber *)left CMMatrix:(CMMatrix *)right;
+ (CMMatrix *)CMMatrix:(CMMatrix *)left NSNumber:(NSNumber *)right;
+ (CMMatrix *)CMMatrix:(CMMatrix *)left CMMatrix:(CMMatrix *)right;

@end
并通过创建编码的方法名并调用它来实现重载方法

还有更好的主意吗

编辑

以下是我的重载逻辑:

@implementation NSObject (CMOverloading)

- (NSString *)overloadingClassName
{
    return NSStringFromClass([self class]); // Override this to handle class clusters
}

- (id)callOverloadedMethod:(Class)method withObject:(id)other
{
    NSString *methodName = [NSString stringWithFormat:@"%@:%@:", [self overloadingClassName], [other overloadingClassName]];
    SEL selector = NSSelectorFromString(methodName);
    return objc_msgSend(method, selector, self, other);
}

@end
编辑2

“重载库”的基类是
NSProxy
,因此库的用户无法实例化它

编辑3

简化宏的实现:

#define CMOverloadingMethod(_return, _left, _right) \
+ (_return *)_left:(_left *)left _right:(_right *)right

#define CMOverloadedMethod(_type, _object) \
return [self callOverloadedMethod:[_type class] withObject:(_object)]
重载方法仍然需要一个(简单的)单一实现,这里,直接在
NSObject
中:

- (id)multiply:(id)right
{
    CMOverloadedMethod(CMMultiply, right);
}
并通过
NSNumber
实现:

@implementation CMMultiply (NSNumber)

CMOverloadingMethod(NSNumber, NSNumber, NSNumber)
{
    return @([left doubleValue] * [right doubleValue]);
}

@end
要实现此语法

NSLog(@"%@ %@ %@ %@", [x multiply:v], [x multiply:m], [m multiply: i], [v multiply:x]);
您必须在每个数学类(向量、矩阵)中实现一个乘法方法,并在NSNumber上实现一个类别方法。问题是,您还希望能够传递任何参数,而Objective-C(多个名称相同但参数类型不同的方法)不支持这一点

相反,您可以将id作为参数,并在运行时确定类型,或者必须更加详细:

NSLog(@"%@ %@ %@ %@", [x multiplyWithVector:v], 
                      [x multiplyWithMatrix:m],
                      [m multiplyWithMatrix:i],
                      [v multiplyWithScalar:x]);
但这太复杂了,而且,实现这样的数学库会非常慢


为什么不使用简单的结构和函数呢?这已经做了很多次了,而且很有效 C不使用像VC++那样的C++。它引用使用字符串查找的方法,因此不能通过参数重载方法。那么,您最好使用
id
来允许引用任何类型的参数。因此,您的
multiply
方法如下所示:

+ (id)multiplyLeft:(id)left right:(id)right;
@interface NSObject (Math)

- (instancetype)multiply:(id)right;

@end

@implementation NSObject (Math)

- (instancetype)multiply:(id)right
{
    // Feel free to throw an exception here.
    return nil;
}

@end

@implementation NSNumber (Math)

- (instancetype)multiply:(id)right
{
    if ([right isKindOfClass:[NSNumber class]])
    {
        return [NSNumber numberWithInteger:[self integerValue] * [right integerValue]];
    }
    else
    {
    // Feel free to throw an exception here.
        return nil;
    }
}

@end
这不是最好的解决办法

您可以使用类别,然后您将有一个如下开头的解决方案:

+ (id)multiplyLeft:(id)left right:(id)right;
@interface NSObject (Math)

- (instancetype)multiply:(id)right;

@end

@implementation NSObject (Math)

- (instancetype)multiply:(id)right
{
    // Feel free to throw an exception here.
    return nil;
}

@end

@implementation NSNumber (Math)

- (instancetype)multiply:(id)right
{
    if ([right isKindOfClass:[NSNumber class]])
    {
        return [NSNumber numberWithInteger:[self integerValue] * [right integerValue]];
    }
    else
    {
    // Feel free to throw an exception here.
        return nil;
    }
}

@end
同样,这不是一个很好的解决方案,但它允许你写下你想要的东西


祝你好运。

你也可以使用C++。Objective-C++非常强大。Clang现在支持C++ 11。C++是很好的一种,混合两种语言的代码是非常干净和容易的。

< P>这是我使用的最后设计,用反射来解决类型。我仍然使用类作为重载函数的容器,基本上使用那些容器类型作为vTable:

#define CMOverloadingMethod(_return, _left, _right) \
+ (_return *)_left:(_left *)left _right:(_right *)right

#define CMOverloadedMethod(_type, _object) \
return [self callOverloadedMethod:[_type class] withObject:(_object)]

- (id)callOverloadedMethod:(Class)method withObject:(id)other
{
    Class thisClass = [self class];
    Class nextClass = [other class];
    Class methodClass = object_getClass(method);

    // Find the appropriate overload:
    Class thisClass2 = Nil;
    do
    {
        thisClass2 = thisClass;

        Class otherClass = nextClass;
        Class otherClass2 = Nil;
        do
        {
            otherClass2 = otherClass;
            SEL selector = NSSelectorFromString(MSSTR(@"%@:%@:", NSStringFromClass(thisClass), NSStringFromClass(otherClass)));
            if (class_respondsToSelector(methodClass, selector))
                return objc_msgSend(method, selector, self, other);
            else
                otherClass = class_getSuperclass(otherClass);
        } while (otherClass != otherClass2 && otherClass && otherClass2);
        thisClass = class_getSuperclass(thisClass);
    } while (thisClass != thisClass2 && thisClass && thisClass2);

    [NSException raise:NSInvalidArgumentException format:@"Cannot resolve overloaded method in class %@ for objects typed %@ and %@.", NSStringFromClass(method), NSStringFromClass([self class]), NSStringFromClass([other class])];
    return nil;
}

为每个操作创建一个类是疯狂的!如果你真的需要运算符重载,你应该仔细考虑一个方法,将你的方法的参数指定为类型<代码> ID <代码>。然后您可以使用
isKindOfClass:
来决定您需要对它们做什么。@b这个“每个重载一个类”用于类类别,以便以后可以添加不同的重载。实际上,我正在尝试在字符串匹配的顶部实现基于类型的vtable查找。我说,这是为了好玩。对于真正的交易,我宁愿直接去GMP/MPFR或类似。我有一个在同一页上的C++,只是平不喜欢,讨厌和讨厌它。所以,不,我会坚持客观C或纯C。哦,天哪,如果莱纳斯说这不好。。。哈哈,好的,很好。完成后一定要发布解决方案。也许我会发布一个C++版本。好,你说你在文章中你试图模仿C++,然后我指出你可以很容易地交织C++和你的目标语言,你说你讨厌它。这很有道理。我保证这样的组合会更干净。别担心它的表现可能会超过它一个数量级。但是抱歉我说了什么,哥们。如果我用C++来做这个,我就必须用C++来重写整个库,所以,EH,No.C++重载可以告诉<代码> int >代码>除了<代码> ID>代码>(ObjuleC对象)但是,它不能区分<代码> NSULT**/COD>除了 CMVoS**/COD>之外,因为它们都是代码> ID<代码>代码> C++。因此,需要一种原生的Objective-C方法。既然C++帮不了什么,那为什么还要麻烦呢?那是一个更好的论点,然后“莱纳斯不喜欢”。我不知道你用什么类型的森林去了多远。你看过boost吗?对于这样的事情,这是我见过的所有其他让我感到羞耻的事情。。别误会我,我喜欢O-C,但是对于矩阵数学,我会用C++。