什么是对象
面向对象编程(Object Oriented Programming)是一种编程风格,旨在让思维编程更接近思考现实世界。
在编程世界里,对象是独立单元,每一个都有自己的身份,像真实世界那样,像苹果,马克杯等等,每一个都有独一无二的 identity (身份)。
有两个一模一样的马克杯,但是他们仍然是分开的两个独立个体。
一个对象可能包含其他对象,但它们仍然是不同的对象。
对象用属性来描述它们的特征。例如,一辆车可以是红色或蓝色,一个杯子可以是满的或空的,等等。
一个属性描述了一个对象的当前状态。
对象可以有多个属性(马克杯可以是空的,红色的和大的)。
对象的状态与其类型无关;比如:一个杯可能充满水,另一个杯可能是空的。
在现实世界中,每个对象都以自己的方式行事。汽车是移动,电话是铃响,等等。这同样适用于对象。
所以对象的类型有三个维度表示,identity(标识),attributes(属性),behavior(行为)
在编程中,一个对象是独立的,有自己的身份(标识)。它与其他对象是分开的。
每个对象都有自己的属性,描述了它的当前状态。每个对象都展示自己的行为,这表明他们可以做什么。
在编程中,对象并不总是代表物理项目。
例如,一个编程对象可以代表日期,时间,银行账户。银行账户不是有形的;你看不见它或者触摸它,但它仍然是一个明确的对象 - 它有自己的身份,属性和行为。
什么是类
在编程中,type 类型用于引用类名:我们正在创建一个特定类型的对象。
属性也被称为属性或数据。
方法
方法是类行为的另一个术语。一个方法基本上是一个属于一个类的函数。
方法类似于函数 - 它们是被调用的代码块,也可以执行操作并返回值。
一个类的例子
例如,如果我们正在创建一个银行项目,我们可以给我们的类以下特征:
名称:BankAccount
属性:accountNumber,余额: dateOpened
行为:open(), close(), deposit()
该类指定每个对象应具有已定义的属性和行为。但是,它没有指定实际的数据是什么;它只提供一个定义。
一旦我们编写了这个类,我们就可以继续创建基于这个类的对象。
每个对象被称为一个类的实例。创建对象的过程称为实例化。
每个对象都有自己的身份(标识),数据(属性)和行为。
声明一个类
用关键字 class 定义类。按照带有类名和类体的关键字,用一组大括号(花括号)括起来。
以下代码声明了一个名为 BankAccount 的类:
class BankAccount {
};
一个类的定义必须跟一个分号。
在大括号内定义类的所有属性和行为(或成员)。
您还可以为类的成员定义访问说明符。
已经使用 public 关键字定义的成员可以从类外部访问,只要它在类对象范围内的任何位置。
你也可以指定一个类的成员为 private 或 protected 的。
创建一个类
让我们用一个公开的方法创建一个类,并打印出 "Hi,W3cschool"。
class BankAccount {
public:
void sayHi() {
cout << "Hi,W3cschool" << endl;
}
};
下一步是实例化我们的 BankAccount 类的一个对象,就像我们定义一个类型的变量一样,区别在于我们的对象的类型是 BankAccount。
int main()
{
BankAccount test;
test.sayHi();
}
我们的名为 test 的对象已经拥有了所有类的成员。
注意用于访问和调用对象的方法的点分隔符 . (英文点符号)
我们必须在使用它之前声明一个类,就像我们对函数做的一样。
抽象类
数据抽象是向外界提供唯一重要信息的概念。
这是一个表示基本特征而不包括实现细节的过程。
一个好的现实世界的例子是一本书:当你听到书,你不知道确切的细节,即页数,颜色,大小,但你明白一本书的想法 - 抽象这本书。
抽象的概念是我们关注基本本质,而不是一个特定例子的具体特征。
抽象意味着我们可以有一个完全与任何具体实例分离的想法或概念。
它是面向对象编程的基本组成部分之一。
例如,当你使用 cout 时,你实际上使用了类 ostream 的 cout 对象。使流数据标准输出。
cout << "Hello Loen!" << endl;
在这个例子中,不需要知道 cout 如何在用户的屏幕上显示文本。
你需要知道的是能够使用它,它是公共接口。
抽象允许我们写一个单一的银行账户类,然后根据类创建不同的对象。
抽象是其他面向对象基础的基础,例如继承和多态。
封装
封装这个词的部分含义是 “围绕” 一个实体的想法,不仅仅是把内在的东西放在一起,而且还要保护它。
在面向对象方面,封装不仅仅是将一个类中的属性和行为组合在一起,这也意味着限制进入该类的内部工作。
这里的关键原则是一个对象只显示其他应用程序组件需要有效运行应用程序的内容。其他一切都被保留在视野之外(隐藏)。
这被称为数据隐藏。
例如,如果我们使用 BankAccount 类,我们不希望程序的其他部分进入并更改任何对象的 balance ,而无需通过 deposit() 或 withdraw() 行为。
我们应该隐藏这个属性,控制对它的访问,所以它只能被对象本身访问。这样,balance 不能直接从物体外面改变,只能用其方法进行访问。
这也被称为“黑匣子”,是指关闭对象的内部工作区域,除了我们想要公开的部分。
这使我们可以在不改变整个程序的情况下改变方法的属性和实现。例如,我们可以稍后再回来,更改 balance 属性的数据类型。
总之封装的好处是:
- 控制数据访问或修改的方式。
代码更加灵活,易于根据新的要求进行更改。
更改代码的一部分而不影响其他代码部分。
访问说明符
访问说明符用于为特定成员设置访问级别。
访问说明符的三个级别是 public, protected, 和 private.
一个 public 成员可以从类以外的任何地方访问,也可以在类对象的范围内的任何地方访问。
例如:
#include <iostream>
#include <string>
using namespace std;
class myClass {
public:
string name;
};
int main() {
myClass myObj;
myObj.name = "Eeedong Loen";
cout << myObj.name;
return 0;
}
//输出 "Eeedong Loen"
name 属性是 public (公共的);它可以从代码之外访问和修改。
访问修饰符只需要声明一次; 多个成员可以遵循单个访问修饰符。注意 public 关键字后面的冒号(:)
Private
一个 private 成员不能从类外访问(对外不可见);只能从类内部进行访问。
#include <iostream>
#include <string>
using namespace std;
class myClass {
public:
void setName(string x) {
name = x;
}
private:
string name;
};
int main() {
myClass myObj;
myObj.setName("Loen");
return 0;
}
name 属性是 private 私有的,不能从外部访问。
setName() 方法是 public 并在方法中使用到了 name 属性
如果未定义访问说明符,则默认情况下,类的所有成员都设置为 private。
我们可以添加另一个公共方法来获取属性的值。
class myClass {
public:
void setName(string x) {
name = x;
}
string getName() {
return name;
}
private:
string name;
};
getName() 方法返回 私有属性 name 的值。
#include <iostream>
#include <string>
using namespace std;
class myClass {
public:
void setName(string x) {
name = x;
}
string getName() {
return name;
}
private:
string name;
};
int main() {
myClass myObj;
myObj.setName("Loen");
cout << myObj.getName();
return 0;
}
//输出 "Loen"
我们使用封装来隐藏来自外部代码的名称属性。然后我们使用公共方法提供访问权限。我们的类数据只能通过这些方法读取和修改。
这样允许更改方法和属性的实现,而不会影响外部代码。
构造函数
类构造函数是类的特殊成员函数。无论何时在该类中创建新对象,都会执行它们。
构造函数的名称与该类的名称完全相同。它没有返回类型,甚至 void 类型。
例如:
class myClass {
public:
myClass() {
cout <<"Loen";
}
void setName(string x) {
name = x;
}
string getName() {
return name;
}
private:
string name;
};
int main() {
myClass myObj;
return 0;
}
//输出 "Loen"
在创建一个 myClass 类型的对象时,构造函数会自动调用。
构造函数对于设置某些成员变量的初始值非常有用。
默认的构造函数没有参数。但是,在需要时,可以将参数添加到构造函数中。
这可以在创建对象时为其分配一个初始值,如下例所示:
class myClass {
public:
myClass(string nm) {
setName(nm);
}
void setName(string x) {
name = x;
}
string getName() {
return name;
}
private:
string name;
};
我们定义了一个构造函数,该构造函数接受一个参数,并使用 setName() 方法将其分配给 name 属性。
创建对象时,您现在需要传递构造函数的参数,就像调用函数时一样:
class myClass {
public:
myClass(string nm) {
setName(nm);
}
void setName(string x) {
name = x;
}
string getName() {
return name;
}
private:
string name;
};
int main() {
myClass ob1("eeedong");
myClass ob2("Amy");
cout << ob1.getName();
}
//输出 "eeedong"
我们定义了两个对象,并使用构造函数传递每个对象的 name 属性的初始值。
可能有多个构造函数他们有不同数量的参数。