类和对象


title: c++之类和对象
tags:


类和对象

起初一看,这个概念貌似在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++第八版,纯属小白自学!!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351