C++复合成员对象的getter与setter正确实现方法
作为类成员的自定义对象的Getter/Setter实现
你已经实现了带完整getter/setter的DateOfBirth类,将它的实例作为其他类的私有成员时,getter/setter的实现逻辑和内置类型成员核心一致,只需要根据封装需求选择对应的值/引用/指针返回形式即可,以下是工业界常用的三种实现方案:
前提参考:DateOfBirth类基础实现
class DateOfBirth { private: int month; int day; int year; public: DateOfBirth(int m = 1, int d = 1, int y = 2000) : month(m), day(d), year(y) {} int getMonth() const { return month; } void setMonth(int m) { month = m; } int getDay() const { return day; } void setDay(int d) { day = d; } int getYear() const { return year; } void setYear(int y) { year = y; } };
方案1:值语义实现(小型对象首选,最常用)
适合DateOfBirth这种占用空间小、不需要多态的成员对象,核心是避免暴露内部成员的可写权限,同时减少不必要的对象拷贝:
#include <iostream> class Person { private: DateOfBirth dob; // 私有成员:出生日期对象 public: // Getter:返回const引用,无拷贝开销,同时禁止外部修改内部对象 const DateOfBirth& getDob() const { return dob; } // Setter:接收const引用参数,拷贝赋值给内部成员 void setDob(const DateOfBirth& newDob) { dob = newDob; } // 重载便利setter:支持直接传入年月日,无需外部提前构造DateOfBirth对象 void setDob(int m, int d, int y) { dob.setMonth(m); dob.setDay(d); dob.setYear(y); } }; // 调用示例 int main() { Person zhangsan; // 两种赋值方式 DateOfBirth tempDob(10, 1, 1999); zhangsan.setDob(tempDob); zhangsan.setDob(10, 1, 1999); // 读取值 const DateOfBirth& dob = zhangsan.getDob(); std::cout << dob.getYear() << std::endl; // 正常输出1999 // dob.setYear(2000); // 编译报错,const引用无法调用非const的setter return 0; }
方案2:智能指针成员实现(大对象/多态场景适用)
如果成员对象较大、需要运行时多态,通常会用智能指针持有成员,此时setter需要明确所有权转移逻辑,getter禁止暴露可写的指针所有权:
#include <memory> class Person { private: std::unique_ptr<DateOfBirth> dob; public: // Getter:返回const裸指针,不转移所有权,禁止修改内部对象 const DateOfBirth* getDob() const { return dob.get(); } // Setter:接收unique_ptr参数,通过move转移所有权 void setDob(std::unique_ptr<DateOfBirth> newDob) { dob = std::move(newDob); } };
方案3:代理方法实现(高封装性场景适用)
如果你不希望外部代码拿到完整的DateOfBirth对象,可以直接在容器类中实现代理读写方法,直接操作内部成员的字段,还可以统一加参数合法性校验:
class Person { private: DateOfBirth dob; public: // 代理读方法 int getBirthMonth() const { return dob.getMonth(); } int getBirthDay() const { return dob.getDay(); } int getBirthYear() const { return dob.getYear(); } // 代理写方法,可统一加业务校验 void setBirthDate(int m, int d, int y) { // 示例校验:月份必须在1-12区间 if (m < 1 || m > 12) return; dob.setMonth(m); dob.setDay(d); dob.setYear(y); } };
避坑提醒:不要在getter中返回内部成员的非const引用/非const指针,否则外部代码可以绕过类的访问控制直接修改私有成员,彻底破坏类的封装性。如果需要修改内部对象的字段,优先使用整体setter替换对象,或者通过代理setter完成字段修改。
内容的提问来源于stack exchange,提问作者Purmp
相关产品推荐
相关产品推荐

