见下面的代码,我很困惑为什么我们需要getter和setter?
#include<iostream>
#include<cstring>
using namespace std;
class car
{
char name[30];
int price;
public:
void get_data(char* n,int p)
{
strcpy(name,n);
price=p;
}
void set_data()
{
cout<<"Name: "<<name<<endl;
cout<<"Price:"<<price<<endl;
}
///Lets add the idea of constructor
car()
{
cout<<"constructor has been called"<<endl;
}
car(char *n, int p)
{
cout<<"2nd constructor has been called"<<endl;
strcpy(name,n);
price=p;
}
~car()
{
cout<<"Name: "<<name<<endl;
cout<<"Price:"<<price<<endl;
}
};
int main()
{
car A("BMW",1000);
car B("Audi",2000);
}
我在问如果构造函数可以设置值并打印值,为什么我们需要 getter 和 setter? 为什么会有吸气手和二传手的想法?
你是对的,getter 和 setter 通常是非常糟糕的想法,这表明你的类的抽象是破碎的/不存在的。但你强调的原因并不是真的。
您需要仔细考虑每个类应该做什么。目标是每个类应该做一件事,然后它们应该是可组合的。这使您可以更轻松地创建新功能并维护现有代码。
例如,你的汽车类不是很好,因为它不允许我拥有我不想随机打印内容的汽车。这实际上是两个类 - 一个Car类和一个RandomlyPrintingContentCar。
但话又说回来,汽车类根本不是一个真正的类。它没有什么真正起作用的。它只是两个字段的方便聚合。而且有一堆蹩脚的 C 字符串和缓冲区溢出,甚至将其描述为方便也太慷慨了。
类很有用,因为它们可以具有抽象接口,允许您隐藏其数据成员的状态。这几乎直接排除了只为所有内容提供 getter 和 setter,因为这样什么都不会隐藏。不提供 getter(或者更常见的是,二传手(是一个非常强大的工具,也是使用类的要点之一。
构造函数确实可以设置类变量的值。但是,每个对象的生存期只能发生这种情况一次,因为构造函数仅在实例化对象时调用。如果用户想稍后在程序中更改变量的值怎么办?这就是二传手的用途。资源库允许更改类中的变量。您还希望 getter 在程序运行时的任何时候访问该变量。
至于析构函数,它们通常保留用于垃圾回收,不应用于获取和设置变量。
- 您的get_data不是让用户获取数据,而是设置对象的数据。更好的命名是getName((,setName(char *n(和getPrice((和setPrice(int p(。
- 考虑重载您的构造函数,现在您想对代码进行一些更改,例如 price 不能为负数或名称不能为 null。
-
更好的编码风格是:
类车 { 字符名称[30]; 整数价格; 公共: 空集名称(字符 *n( { if(n == NULL( n = "; strcpy(name,n(;
} void setPrice(int p) { if(p <0) p = 0; price = p; } int getPrice() { return price; } char * getName() { return name; } ///Lets add the idea of constructor with default values car() { cout<<"constructor has been called"<<endl; setPrice(0); setName(""): } car(char *n, int p) { cout<<"2nd constructor has been called"<<endl; setName(n); setPrice(p); } ~car() { cout<<"Name: "<<name<<endl; cout<<"Price:"<<price<<endl; } };
-
现在,如果 price 得到了更多的验证,则所有验证都将添加到一个函数 setPrice 中,而不是在每个构造函数中以不同的方式添加。名字也一样。
- 您的set_data只写给 cout。 如果以后你想输出到文件怎么办?所以最好有getPrice((并在main中使用它来写入cout。