类和对象
title: c++之类和对象
tags:
- 语言工具
- c++
categories: c++
date: 2019-02-22
thumbnail: https://img.haomeiwen.com/i16271012/b179a966838ec731.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240
类和对象
起初一看,这个概念貌似在c语言中并没有存在过,应该是属于c++的核心之一了吧,下面开始仔细学习。
首先,提出以下问题以供思考:
• 什么是类和对象;
• 类如何帮助您整合数据和处理数据的函数;
• 构造函数、复制构造函数和析构函数;
• 移动构造函数是什么;
• 封装和抽象等面向对象的概念;
• this 指针;
• 结构是什么,它与类有何不同。
什么是类
要在程序中模拟人,需要一个结构,如图所示,将定义人的属性(数据)以及人可使用这些属性执行的操作(函数)整合在一起。这种结构就是类。
image.png
声明类
要声明类,可使用关键字 class,并在它后面依次包含类名,一组放在{}内的成员属性和成员函数,
以及结尾的分号。
模拟人类的类类似于下面这样:
class Human
{
// Member attributes:
string name;
string dateOfBirth;
string placeOfBirth;
string gender;
// Member functions:
void Talk(string textToTalk);
void IntroduceSelf();
...
};
封装指的是将数据以及使用它们的函数进行逻辑编组,这是面向对象编程的重要特征。
创建 Human 对象与创建其他类型(如 double)的实例类似:
double pi= 3.1415;
Human firstMan;
就像可以为其他类型(如 int)动态分配内存一样,也可使用 new 为 Human 对象动态地分配内存:
int* pointsToNum = new int;
delete pointsToNum;
Human* firstWoman = new Human();
delete firstWoman;
使用句点运算符访问成员
一个人的例子是 Adam,男性,1970 年出生于阿拉巴马州。firstMan 是 Human 类的对象,是这个
类存在于现实世界(运行阶段)的化身:
Human firstMan;
firstMan.dateOfBirth = "1970"; // 类声明表明,firstMan 有 dateOfBirth 等属性,可使用句点运算符(.)
firstMan.IntroduceSelf(); 来访问
如果有一个指针 firstWoman,它指向 Human 类的一个实例,则可使用指针运算符(->)来访问成
员,也可使用 间接运算符() 来获取对象,再使用 句点运算符 来访问成员:
Human firstWoman = new Human();
(*firstWoman).IntroduceSelf();
使用指针运算符(->)访问成员
#include <iostream>
#include <string>
using namespace std;
class Human
{
public:
string name;
int age;
void IntroduceSelf()
{
cout << "I am " + name << " and am ";
cout << age << " years old" << endl;
}
};
int main()
{
Human firstMan;
firstMan.name = "Adam";
firstMan.age = 30;
Human firstWoman;
firstWoman.name = "Eve";
firstWoman.age = 28;
firstMan.IntroduceSelf();
firstWoman.IntroduceSelf();
}
输出:I am Adam and am 30 years old
I am Eve and am 28 years old
关键字 public 和 private
作为类的设计者,您可使用 C++关键字 public
和 private 来指定哪些部分可从外部(如 main( ))访问,哪些部分不能。
程序实例:
class Human
{
private:
// Private member data:
int age;
string name;
public:
int GetAge()
{
return age;
}
void SetAge(int humansAge)
{
age = humansAge;
}
// ...Other members and declarations
};
Human eve;
cout << eve.age; // compile error
cout << eve.GetAge(); // OK
构造函数
构造函数是一种特殊的函数,它与类同名且不返回任何值。
声明如下:
一、
class Human
{
public:
Human(); // declaration of a constructor
};
二、
class Human
{
public:
Human()
{
// constructor code here
}
};
三、
class Human
{
public:
Human(); // constructor declaration
};
// constructor implementation (definition)
Human::Human()
{
// constructor code here
}
补充: ::被称为作用域解析运算符。例如,Human::dateOfBirth 指的是在 Human 类 中 声明的变
量 dateOfBirth,而::dateOfBirth 表示全局作用域中的变量 dateOfBirth。
使 用 构 造 函 数 初 始 化 类 成 员 变 量
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
string name;
int age;
public:
Human() // constructor
{
age = 1; // initialization
cout << "Constructed an instance of class Human" << endl;
}
void SetName (string humansName)
{
name = humansName;
}
void SetAge(int humansAge)
{
age = humansAge;
}
void IntroduceSelf()
{
cout << "I am " + name << " and am ";
cout << age << " years old" << endl;
}
};
int main()
{
Human firstWoman;
firstWoman.SetName("Eve");
firstWoman.SetAge (28);
firstWoman.IntroduceSelf();
}
输出:
Constructed an instance of class Human
I am Eve and am 28 years old
重载构造函数
历程
猪猪猪猪猪猪猪
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
string name;
int age;
public:
Human()
{
age = 0;
cout << "Default constructor: name and age not set" << endl;
}
Human(string humansName, int humansAge)
{
name = humansName;
age = humansAge;
cout << "Overloaded constructor creates ";
cout << name << " of " << age << " years" << endl;
}
};
int main()
{
Human firstMan;
Human firstWoman ("Eve", 20);
}
输出:
Default constructor: name and age not set
Overloaded constructor creates Eve of 20 years
包含初始化列表的构造函数
程序清单 9.6 接受带默认值的参数的默认构造函数,并使用初始化列表来设置成员
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
int age;
string name;
public:
Human(string humansName = "Adam", int humansAge = 25)
:name(humansName), age(humansAge)
{
cout << "Constructed a human called " << name;
cout << ", " << age << " years old" << endl;
}
};
int main()
{
Human adam;
Human eve("Eve", 18);
return 0;
}
输出:
Constructed a human called Adam, 25 years old
Constructed a human called Eve, 18 years old
析构函数 析构函数 析构函数
与构造函数一样,析构函数也是一种特殊的函数。构造函数在实例化对象时被调用,而析构函数
在对象销毁时自动被调用。
析构函数看起来像一个与类同名的函数,但前面有一个腭化符号(~)。因此,Human 类的析构函
数的声明类似于下面这样:
①
class Human
{
~Human(); // declaration of a destructor
};
②
class Human
{
public:
~Human()
{
// destructor code here
}
};
③
class Human
{
public:
~Human();
};
Human::~Human()
{
}
析构函数的功能:每当对象不再在作用域内或通过 delete 被删除进而被销毁时,都将调用析构函数。这使得析构函数成为重置变量以及释放动态分配的内存和其他资源的理想场所。
一 个 简 单 的 类,它 封 装 了 字 符 缓 冲 区 并 通 析 构 函 数 释 放 它
#include <iostream>
#include <string.h>
using namespace std;
class MyString
{
private:
char* buffer;
public:
MyString(const char* initString)
{
if(initString != NULL)
{
buffer = new char [strlen(initString) + 1];
strcpy(buffer, initString);
}
else
buffer = NULL;
}
~MyString()
{
cout << "Invoking destructor, clearing up" << endl;
if (buffer != NULL)
delete [] buffer;
}
int GetLength()
{
return strlen(buffer);
}
const char* GetString()
{
return buffer;
}
};
int main()
{
MyString sayHello("Hello from String Class");
cout << "String buffer in sayHello is " << sayHello.GetLength();
cout << " characters long" << endl;
cout << "Buffer contains: " << sayHello.GetString() << endl;
}
输出:
String buffer in sayHello is 23 characters long
Buffer contains: Hello from String Class
Invoking destructor, clearing up
使用关键字explicit可以避免隐式转换
this指针
在类中,关键字 this 包含当前对象的地址,换句话说,其值为&object。
分析如下:
class Human
{
private:
void Talk (string Statement)
cout << Statement;
}
public:
void IntroduceSelf()
{
Talk("Bla bla"); // same as Talk(this, "Bla Bla")
}
};
在这里,方法 IntroduceSelf( )使用私有成员 Talk( )在屏幕上显示一句话。实际上,编译器将在调用
Talk 时嵌入 this 指针,即 Talk(this, “Blab la”)
将 sizeof( )用于类
运算符 sizeof( )用于确定指定类型需要多少内存,单位为字节。这个运算符也可用于类,在这种情
况下,它将指出类声明中所有数据属性占用的总内存量,单位为字节。
**应用如下**
#include <iostream>
#include <string.h>
using namespace std;
class MyString
{
private:
char* buffer;
public:
MyString(const char* initString) // default constructor
{
buffer = NULL;
if(initString != NULL)
{
buffer = new char [strlen(initString) + 1];
strcpy(buffer, initString);
}
}
MyString(const MyString& copySource) // copy constructor
{
buffer = NULL;
if(copySource.buffer != NULL)
{
buffer = new char [strlen(copySource.buffer) + 1];
strcpy(buffer, copySource.buffer);
}
}
~MyString()
{
delete [] buffer;
}
int GetLength()
{ return strlen(buffer); }
const char* GetString()
{ return buffer; }
};
class Human
{
private:
int age;
bool gender;
MyString name;
public:
Human(const MyString& InputName, int InputAge, bool gender)
: name(InputName), age (InputAge), gender(gender) {}
int GetAge ()
{ return age; }
};
int main()
{
MyString mansName("Adam");
MyString womansName("Eve");
cout << "sizeof(MyString) = " << sizeof(MyString) << endl;
cout << "sizeof(mansName) = " << sizeof(mansName) << endl;
cout << "sizeof(womansName) = " << sizeof(womansName) << endl;
Human firstMan(mansName, 25, true);
Human firstWoman(womansName, 18, false);
cout << "sizeof(Human) = " << sizeof(Human) << endl;
cout << "sizeof(firstMan) = " << sizeof(firstMan) << endl;
cout << "sizeof(firstWoman) = " << sizeof(firstWoman) << endl;
return 0;
}
输出;
sizeof(MyString) = 4
sizeof(mansName) = 4
sizeof(womansName) = 4
sizeof(Human) = 12
sizeof(firstMan) = 12
sizeof(firstWoman) = 12
结构不同于类的地方
关键字 struct 来自 C 语言,在 C++编译器看来,它与类及其相似,差别在于程序员未指定时,默
认的访问限定符(public 和 private)不同。因此,除非指定了,否则结构中的成员默认为公有的(而
类成员默认为私有的);另外,除非指定了,否则结构以公有方式继承基结构(而类为私有继承)。
结构可以不注明公有的部分。
声明友元
不能从外部访问类的私有数据成员和方法,但这条规则不适用于友元类和友元函数。要声明友元
类或友元函数,可使用关键字 friend,
使用关键字 friend 让外部 函数 DisplayAge( ) 能够访问 私有数据成员
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
friend void DisplayAge(const Human& person); //函数 DisplayAge( )是全局函数,还是 Human 类的友元,因此能够访问Human 类的私有数据成员。
string name;
int age;
public:
Human(string humansName, int humansAge)
{
name = humansName;
age = humansAge;
}
};
void DisplayAge(const Human& person)
{
cout << person.age << endl;
}
int main()
{
Human firstMan("Adam", 25);
cout << "Accessing private member age via friend function: ";
DisplayAge(firstMan);
return 0;
}
输出
Accessing private member age via friend function: 25
使用关键字 friend 让 外部类 Utility 能够访问 私有数据成员
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
friend class Utility; //指出 Utility 类是 Human 类的友元,该声明让 Utility 类的所有方法都能访问 Human 类的私有数据成员和方法。
string name;
int age;
public:
Human(string humansName, int humansAge)
{
name = humansName;
age = humansAge;
}
};
class Utility
{
public:
static void DisplayAge(const Human& person)
{
cout << person.age << endl;
}
};
int main()
{
Human firstMan("Adam", 25);
cout << "Accessing private member age via friend class: ";
Utility::DisplayAge(firstMan);
return 0;
}
输出:
Accessing private member age via friend class: 25
共用体
共用体是一种特殊的类,每次只有一个非静态数据成员处于活动状态。因此,共用体与类一样,
可包含多个数据成员,但不同的是只能使用其中的一个。
要声明共用体,可使用关键字 union ,如下所示
union UnionName
{
Type1 member1;
Type2 member2;
…
TypeN memberN;
};
要实例化并使用共用体,可像下面这样做:
UnionName unionObject;
unionObject.member2 = value;
猪猪猪猪猪:与结构类似,共用体的成员默认也是公有的,将 sizeof()用于共用体时,结果总是为共用体最大成员的长度,即便该成员并不处于活动状态。
聚合初始化
下面的结构符合成为聚合类型的条件:
struct Aggregate1
{
int num;
double pi;
};
可将其作为一个整体进行初始化:
Aggregate1 a1{ 2017, 3.14 };
再来看一个例子:
struct Aggregate2
{
int num;
char hello[6];
int impYears[5];
};
对于这个结构,可像下面这样进行初始化:
Aggregate2 a2 {42, {'h', 'e', 'l', 'l', 'o'}, {1998, 2003, 2011, 2014, 2017}};
文章依据21天学通C++第八版,纯属小白自学!!!!