分类中究竟能不能增加成员变量?

本文深入探讨了Objective-C分类中添加成员变量的机制与注意事项,通过实例展示了如何正确地在分类中引入成员变量,并解释了@dynamic关键字的作用及如何消除相关警告。文章还介绍了动态绑定的概念及其在Objective-C中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


之前在相关的OC书上看到的关于分类的说法是:只能增加方法,但是不能增加成员变量。
但是今天,在一个练习中,需要用到增加一个成员变量,于是写下了下列代码:(已提出来单独讲此问题)

NSObject+Test.h

 #import <Foundation/Foundation.h>

 @interface NSObject (Test)

 @property (nonatomic,copy) NSString *str;

 @end

NSObject+Test.m

 #import "NSObject+Test.h"

 @implementation NSObject (Test)

 - (void)setStr:(NSString *)str {
    NSLog(@"%@",str);
 }
 @end

(在别处已创建类对象,并调用setter方法赋值str)


结果这是可行的,没有error,只有warning,也打印成功了

Property 'str' requires method 'str' to be defined - use @dynamic or provide a method implementation in this category

查出来去除警告的方法:

http://stackoverflow.com/questions/2520889/objective-c-categories-can-i-add-a-property-for-a-method-not-in-my-category
在.m文件中加一行 @dynamic str
其实就是warning后面提醒我们的意思。


如何理解

@property在通常情况下,除了生成setter和getter方法以外,如果没有该成员变量还会生成成员变量。而在分类中,@property只是生成setter和getter方法(非readonly),
等价于声明了setter和getter方法

 - (void)setStr:(NSString *)str;
 - (NSString *)str;

添加这句话@dynamic str;是告诉编译器,setter和getter方法由用户自己实现,不自动生成。这里涉及一个动态绑定的概念。


此处的@property到底有没有扩充成员变量
我个人想到的简单的方法就是
str赋值
赋值一下,系统就报错了,没定义该变量~


结果:

分类中不能添加成员变量
(大神们,本文很多自己理解,如果有错请指出,初学者“班门弄斧”了)


补充:(@dynamic,动态绑定)

@dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

对于这个警告的消除:
在另一篇文章中还提到了另外的方法:
http://www.cnblogs.com/starer/p/3813674.html

<think>好的,我现在需要解决用户的问题:如果一个函数要访问一个类变量的成员函数,有多少种方法。这个问题看起来是关于C++或类似面向对象编程语言的,因为涉及类和成员函数的访问。首先,我需要回忆相关的知识,确保自己理解正确。 用户提到的是“函数访问类变量的成员函数”。这里的“函数”可能指的是普通函数(非成员函数),或者是类的成员函数。不过根据通常的问题情境,这里可能指的是非成员函数如何访问类的成员函数。因此,我需要考虑不同的访问方式。 首先,我需要明确几个概念:类(class)、成员函数(member function)、访问权限(access specifiers,如public、private、protected)。在C++中,如果成员函数是public的,那么外部函数可以直接通过类的对象来调用它。如果是private或protected的,则不能直接访问,除非使用友元(friend)或其他方法。 接下来,思考可能的解决方案: 1. **通过对象直接调用public成员函数**:这是最直接的方式。如果目标成员函数是public的,外部函数可以创建类的实例,然后使用点运算符(.)或箭头运算符(->,如果是指针)来调用成员函数。 2. **友元函数(Friend Function)**:如果成员函数是private的,可以将外部函数声明为类的友元,这样该函数就可以访问类的私有和保护成员,包括成员函数。 3. **静态成员函数(Static Member Function)**:如果成员函数是静态的,它属于类本身而不是对象,外部函数可以通过类名和作用域解析运算符(::)来调用,无需对象实例。但静态成员函数只能访问静态成员变量和其他静态成员函数,所以这可能有限制。 4. **通过成员函数指针**:在C++中,可以使用指向成员函数的指针来间接调用成员函数。但这通常需要结合对象实例来调用。 5. **使用公共接口(Public Wrapper)**:如果目标成员函数是private的,可以提供一个public的成员函数作为接口,外部函数通过调用这个public接口来间接访问私有成员函数。 6. **继承和protected访问**:如果外部函数是在派生类中,而基类的成员函数是protected的,那么派生类的成员函数可以访问基类的protected成员函数。但这里用户的问题可能更侧重于非成员函数,所以这点可能不太适用。 7. **Lambda表达式或函数对象**:在某些情况下,可能通过传递成员函数给lambda或函数对象来实现访问,但这种方式可能还是依赖于前面提到的几种方法,比如通过对象调用。 现在需要逐一验证这些方法是否有效,并考虑可能的例外情况。 首先,方法1是最基本的,只要成员函数是public的,外部函数就可以通过对象调用。例如: ```cpp class MyClass { public: void myFunction() {} }; void externalFunction() { MyClass obj; obj.myFunction(); // 直接调用public成员函数 } ``` 方法2,友元函数。例如: ```cpp class MyClass { private: void privateFunction() {} friend void friendFunction(); }; void friendFunction() { MyClass obj; obj.privateFunction(); // 友元函数可以访问私有成员 } ``` 方法3,静态成员函数。例如: ```cpp class MyClass { public: static void staticFunction() {} }; void externalFunction() { MyClass::staticFunction(); // 直接调用静态成员函数 } ``` 方法4,成员函数指针。例如: ```cpp class MyClass { public: void myFunction() {} }; void externalFunction() { MyClass obj; void (MyClass::*funcPtr)() = &MyClass::myFunction; (obj.*funcPtr)(); // 通过成员函数指针调用 } ``` 不过,这种方法虽然可行,但通常用于更复杂的场景,比如回调函数,可能不算用户问题中的常见方法。不过确实是一种方式。 方法5,公共接口。例如: ```cpp class MyClass { private: void privateFunction() {} public: void publicInterface() { privateFunction(); } }; void externalFunction() { MyClass obj; obj.publicInterface(); // 通过公共接口调用私有函数 } ``` 这实际上是封装的一种体现,外部函数通过调用public方法来间接访问私有成员函数。 接下来,需要考虑是否还有其他方法。例如,通过类的友元类,然后让外部函数作为友元类的成员函数,但这样可能增加复杂度。或者使用单例模式,但这也属于设计模式的应用,而不是直接的访问方式。 另外,模板元编程中的某些技术可能允许访问,但通常涉及更高级的技巧,可能不在基础方法的范围内。 现在需要确定用户的问题是否包括这些情况。例如,友元函数和静态成员函数是否算作不同的方法,或者通过对象调用public成员函数是否算一种,而通过指针或引用调用是否算同一种方法。 综合来看,主要的方法可能有以下几种: 1. 直接调用public成员函数(通过对象实例) 2. 友元函数 3. 静态成员函数 4. 成员函数指针 5. 公共接口方法 此外,可能还有其他方法,比如通过继承(如派生类中的函数访问基类的protected成员函数),但如果是外部函数,这可能需要派生类中的公共方法,这可能与方法5类似。 因此,总结可能的答案:共有五种方法。但需要再次验证是否每种方法都是独立且有效的。 例如,静态成员函数的情况,如果成员函数本身是静态的,那么确实可以直接调用。但如果原问题中的成员函数是非静态的,那么静态成员函数的方式并不适用。因此,可能静态方法只有在成员函数被声明为static时才有效,这可能是一个前提条件。 同样,成员函数指针的方式虽然存在,但用户可能更关心的是如何通过函数本身来访问,而不需要涉及指针的复杂语法,因此这可能被视为一种较少使用的方法,但仍然是可行的方法。 此外,是否还有其他方法?比如通过绑定器(如std::bind)或lambda表达式,但这些可能还是基于上述方法的变体。 例如: ```cpp #include <functional> class MyClass { public: void myFunction() {} }; void externalFunction() { MyClass obj; auto func = std::bind(&MyClass::myFunction, &obj); func(); // 使用std::bind绑定对象和成员函数 } ``` 这种方法本质上还是通过对象实例调用public成员函数,属于方法1的变体,因此可能不算独立的方法。 综上,主要的独立方法应该是: 1. 直接调用public成员函数(需要public访问权限) 2. 声明为友元函数(访问private/protected成员) 3. 使用静态成员函数(如果目标函数是静态的) 4. 通过公共接口方法(封装私有函数) 5. 使用成员函数指针(需要对象实例) 因此,总共有五种方法。但可能需要进一步确认是否有其他可能性,或者是否某些方法可以合并。 例如,友元函数和友元类中的函数是否算不同的方法?如果用户的问题中的“函数”指的是普通函数,那么友元函数是独立的一种方法,而友元类中的成员函数可能需要通过该类的实例,这可能属于另一种情况,但可能不在用户问题的范围内。 另外,考虑C++11之后的lambda捕获this指针,但同样,这可能需要该lambda在类的成员函数内部,所以可能不适用于外部函数。 最终,我认为主要的五种方法是: 1. 直接调用public成员函数 2. 友元函数访问 3. 静态成员函数调用 4. 公共接口封装 5. 成员函数指针调用 这样分类是否合理? 另外,可能还有其他方式,比如通过继承体系中的protected成员,但外部函数无法直接访问protected成员,必须通过派生类的公共方法,这可能属于公共接口的方式。 因此,最终的答案应该是五种方法,或者可能有四种,如果静态成员函数被视为另一种情况下的特定方法,而用户的问题中的成员函数不是静态的,那么静态方法可能不适用。因此,需要明确问题的范围。 用户的问题并没有限定成员函数的访问权限或是否为静态,因此应该包括所有可能的情况。 因此,总结: 1. 通过对象调用public成员函数 2. 将函数声明为类的友元函数,访问其私有/保护成员函数 3. 调用类的静态public成员函数 4. 通过成员函数指针间接调用(需对象实例) 5. 通过public成员函数作为接口间接调用私有成员函数 因此,共有五种方法。需要确认是否每种都正确。 例如,方法5中的公共接口是否算作独立的方法,还是属于方法1的一部分。如果原问题中的成员函数是private的,那么必须通过public接口,这确实是一种不同的方法,因为需要设计类时提供这样的接口。 因此,这五种方法是独立的,应被算作不同的方法。 现在需要将这些方法用中文清晰地解释,并给出示例,确保用户能够理解。</think>一个函数要访问类的成员函数,主要有以下几种方法,具体取决于成员函数的访问权限和设计需求: --- ### **1. 直接通过对象调用公有(public)成员函数** - **条件**:目标成员函数为`public`权限。 - **方法**:创建类的实例,使用`.`或`->`运算符调用。 - **示例**: ```cpp class MyClass { public: void publicFunc() {} // 公有成员函数 }; void externalFunction() { MyClass obj; obj.publicFunc(); // 直接调用 } ``` --- ### **2. 声明为友元函数(Friend Function)** - **条件**:目标成员函数为`private`或`protected`权限。 - **方法**:在类内声明外部函数为`friend`,使其能直接访问私有成员。 - **示例**: ```cpp class MyClass { private: void privateFunc() {} // 私有成员函数 friend void friendFunction(); // 声明友元函数 }; void friendFunction() { MyClass obj; obj.privateFunc(); // 友元函数可直接调用私有成员 } ``` --- ### **3. 调用静态(static)成员函数** - **条件**:目标成员函数为`static`且`public`。 - **方法**:无需对象实例,直接通过类名调用。 - **示例**: ```cpp class MyClass { public: static void staticFunc() {} // 静态公有成员函数 }; void externalFunction() { MyClass::staticFunc(); // 直接通过类名调用 } ``` --- ### **4. 通过成员函数指针间接调用** - **条件**:成员函数为`public`,需持有对象实例。 - **方法**:定义成员函数指针,结合对象实例调用。 - **示例**: ```cpp class MyClass { public: void memberFunc() {} }; void externalFunction() { MyClass obj; void (MyClass::*funcPtr)() = &MyClass::memberFunc; // 成员函数指针 (obj.*funcPtr)(); // 通过指针调用 } ``` --- ### **5. 通过公有接口间接调用私有函数** - **条件**:类提供公有方法封装私有成员函数。 - **方法**:设计一个`public`方法调用内部`private`方法。 - **示例**: ```cpp class MyClass { private: void privateFunc() {} public: void publicInterface() { privateFunc(); // 公有接口调用私有函数 } }; void externalFunction() { MyClass obj; obj.publicInterface(); // 间接访问私有函数 } ``` --- ### **总结** 共有 **5 种主要方法**: 1. 直接调用公有成员函数(需`public`权限)。 2. 声明为友元函数(突破`private/protected`限制)。 3. 调用静态成员函数(无需实例化对象)。 4. 使用成员函数指针(需对象实例)。 5. 通过公有接口间接调用(封装私有逻辑)。 选择方法时需根据成员函数的访问权限和设计需求灵活决定。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值