Objective-C中重载的仿真方法
我正在用Objective-C编写一个数学库(为了好玩),现在我需要一些方法来模拟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
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>除了