类和对象:

  至此,您探索了简单的程序。这种程序从 main( )开始执行,包含局部变量、全局变量和常量,并
将执行逻辑划分为可接受参数和返回值的函数。前面使用的都是过程性编程风格,未涉及面向对象。
  换句话说,您需要学习 C++面向对象(知人善用是为面向对象)编程基本知识。(终于开始了~)

1.声明类

  要声明类,可使用关键字 class,并在它后面依次包含类名,一组放在{}内的成员属性和成员函数,以及结尾的分号。
  类声明将类本身及其属性告诉编译器。类声明本身并不能改变程序的行为,必须要使用类,就像
需要调用函数一样。
  模拟人类的类类似于下面这样(请暂时不要考虑其中的语法):

class Human
{
// Member attributes:
string name;
string dateOfBirth;
string placeOfBirth;
string gender;
// Member functions:
void Talk(string textToTalk);
void IntroduceSelf();
...
};
  不用说,IntroduceSelf( )将使用 Talk( )以及封装在类 Human 中的一些数据。通过关键字 class,C++提供了一种功能强大的方式,让您能够创建自己的数据类型,并在其中封装属性和使用它们的函数。
  类的所有属性(这里是 name、dateOfBirth、placeOfBirth 和 gender)以及在其中声明的函数(Talk( )和IntroduceSelf( ))都是类(Human)的成员。
  封装指的是将数据以及使用它们的函数进行逻辑编组,这是面向对象编程的重要特征。
  另外,您可能经常遇到术语“方法”,它其实指的就是属于类成员的函数。
  类相当于蓝图,仅声明类并不会对程序的执行产生影响。在程序执行阶段,对象是类的化身。要
使用类的功能,通常需要创建其实例—对象,并通过对象访问成员方法和属性。

我们也可以使用new来为对象动态的申请内存。

Human* firstWoman = new Human(); // dynamically allocated Human
delete firstWoman; // de-allocating memory

注:即Human是申明的类,其firstWoman是对象

  类声明表明,firstMan 有 dateOfBirth 等属性,可使用句点运算符(.)来访问:  
firstMan.dateOfBirth = "1970";
   这是因为从类声明表示的蓝图可知,属性 dateOfBirth 是类 Human 的一部分。仅当实例化了一个对象后,这个属性在现实世界(运行阶段)才存在。句点运算符(.)用于访问对象的属性。
这也适用于 IntroduceSelf( )等方法:
firstMan.IntroduceSelf();

如果有一个指针 firstWoman,它指向 Human 类的一个实例,则可使用指针运算符(->)来访问成员(这将在下一小节介绍),也可使用间接运算符(*)来获取对象,再使用句点运算符来访问成员:

Human* firstWoman = new Human();
(*firstWoman).IntroduceSelf();

总的来说和结构体长得差不多的,目前而言。

关键字:public和private

  信息至少可以分两类:不介意别人知道的数据和保密的数据。对大多数人来说,性别就是一项不
介意别人知道的信息,但收入可能属于隐私。
  C++让您能够将类属性和方法声明为公有的,这意味着有了对象后就可获取它们;也可将其声明
为私有的,这意味着只能在类的内部(或其友元)中访问。作为类的设计者,您可使用 C++关键字 public 和 private 来指定哪些部分可从外部(如 main( ))访问,哪些部分不能。

样例(没有默认构造函数的类):

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;class Human {private:int age;string name;public:int GetAge(){return age;}void SetAge(int humansAge){if(humansAge>0)age=humansAge;//避免被设置为0}
};
int main(void) {Human eve;eve.SetAge(16);cout<<eve.GetAge();//cout<<eve.age  //don't be allowedreturn 0;
}

同样,我们可以简单更改程序,使得其输出更小的年龄。

之所以我们可以达成这一目的,是由于age被声明在private中,不能直接访问它,只能通过GetAge方法进行访问。

  在面向对象编程语言中,抽象是一个非常重要的概念,让程序员能够决定哪些属性只能让类及其成员知道,类外的任何人都不能访问(友元除外

构造函数:

1.声明和实现构造函数

  构造函数是一种特殊的函数,它与类同名且不返回任何值。因此,Human 类的构造函数的声明类

似于下面这样:

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。

何时,如何使用构造函数及重载构造函数:

 注:  可在不提供参数的情况下调用的构造函数被称为默认构造函数。默认构造函数是可选的。
如果您没有提供默认构造函数,编译器将为您创建一个,这种构造函数会创建成员属性,但不会将 POD 类型(如 int)的属性初始化为非零值。如上一张完整程序图
   而如果我们创建了默认构造函数,那么成员属性会初始化为0.

构造函数的使用代码举例:

#include<iostream>
#include<string>
using namespace std;class Human {private:int age;//init 0string name;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(void) {Human firstMan;Human firstWoman("ZHY",16);return 0;
}
您可选择不实现默认构造函数,从而要求实例化对象时必须提供某些参数,也就是删去上代码main中的

Human(){age=0;cout<< "Default constructor: name and age not set."<<endl;}  

带有默认值的构造函数:

class Human
{
private: string name; int age;
public: // overloaded constructor (no default constructor) Human(string humansName, int humansAge = 25) { name = humansName; age = humansAge; cout << "Overloaded constructor creates " << name; cout << " of age " << age << endl; } // ... other members
};
Human adam("Adam"); // adam.age is assigned a default value 25
Human eve("Eve", 18); // eve.age is assigned 18 as specified

注意:

   默认构造函数是调用时可不提供参数的构造函数,而并不一定是不接受任何参数的构造函数。因此,下面的构造函数虽然有两个参数,但它们都有默认值,因此也是默认构造函数:
class Human
{
private:
string name;
int age;
public:
// default values for both parameters
Human(string humansName = "Adam", int humansAge
= 25)
{name = humansName; age = humansAge; cout << "Overloaded constructor creates "; cout << name << " of age " << age; }
};

buffer:n. 缓冲物,起缓冲作用的人;缓冲器;缓存区;老糊涂 v. 保护,保障;缓存

析构函数:

在对象被销毁时自动调用,释放内存(在main函数之后)。

当然,析构函数还是比较困难的,在我们学习的初期,先对它进行了解即可,而无需深研。

声明和实现析构函数
  析构函数看起来像一个与类同名的函数,但前面有一个腭化符号(~)。因此,Human 类的析构函数的声明类似于下面这样:
class Human
{ ~Human(); // declaration of a destructor
};

在类中:

class Human
{
public: ~Human() { // destructor code here }
};

在类外:

class Human
{
public: ~Human(); // destructor declaration
};
// destructor definition (implementation)
Human::~Human()
{ // destructor code here
}
  正如您看到的,析构函数的声明与构造函数稍有不同,那就是包含腭化符号(~)。并且,析构函数的作用与构造函数完全相反。

何时及如何使用析构函数

  每当对象不再在作用域内或通过 delete 被删除进而被销毁时,都将调用析构函数。这使得析构函
数成为重置变量以及释放动态分配的内存和其他资源的理想场所。
使用 char*缓冲区时,您必须自己管理内存分配和释放,因此本书建议不要使用它们,而使用
std::string。std::string 等工具都是类,它们充分利用了构造函数和析构函数,还有将在第 12 章介绍的运算符,让您无需考虑分配和释放等内存管理工作。程序清单 9.7 所示的类 MyString 在构造函数中为一个字符串分配内存,并在析构函数中释放它。

注:

  析构函数不能重载,每个类都只能有一个析构函数。如果您忘记了实现析构函数,编译
器将创建一个伪(dummy)析构函数并调用它。伪析构函数为空,即不释放动态分配的
内存。

腭化符号(~):main函数运行结束后,令之自动调用。

放松时刻:

#include<iostream>
#include<string>
using namespace std;class Human {private:int age;//init 0string name;public:Human(string humansName="Adam",int humansAge=25):name(humansName),age(humansAge){
//      name=humansName;
//      age=humansAge;cout<< "Overloaded constructor creates ";cout<<name<<" of "<<age<<" years."<<endl;}~Human(){cout<<"我啥也没做,哈哈哈"<<endl;}
};
int main(void) {Human adam;Human firstWoman("ZHY",16);cout<<"-------end of main------"<<endl;return 0;
}

continue:

复制构造函数:

浅复制带来的问题:

分析:

    在程序清单 9.7 中运行正常的 MyString 类,为何会导致程序清单 9.8 崩溃呢?相比于程序清单 9.7,程序清单 9.8 唯一不同的地方在于,在 main( )中,将使用 MyString 对象 sayHello 的工作交给了函数UseMyString(),如第 44 行所示。在 main( )中将工作交给这个函数的结果是,对象 sayHello 被复制到形参 str,并在 UseMyString( )中使用它。编译器之所以进行复制,是因为函数 UseMyString( )的参数 str 被声明为按值(而不是按引用)传递。对于整型、字符和原始指针等 POD 数据,编译器执行二进制复制,因此 sayHello.buffer 包含的指针值被复制到 str 中,即 sayHello.buffer 和 str.buffer 指向同一个内存单元。
    二进制复制不复制指向的内存单元,这导致两个 MyString 对象指向同一个内存单元。函数
UseMyString( )返回时,变量 str 不再在作用域内,因此被销毁。为此,将调用 MyString 类的析构函数,而该析构函数使用 delete[]释放分配给 buffer 的内存(如程序清单 9.8 的第 22 行所示)。这将导致 main( )中的对象 sayHello 指向的内存无效,而等 main( )执行完毕时,sayHello 将不再在作用域内,进而被销毁。但这次第 22 行对不再有效的内存地址调用 delete(销毁 str 时释放了该内存,导致它无效)。正是这种重复调用 delete 导致了程序崩溃。

使用复制构造函数确保深复制

//深复制的代码

好了,我没写 ,原因如下:

寄,太难了,看不懂了,构造函数和析构函数的其他用途就不写了,蒟蒻感juo无能为力了。

往下走

this 指针

    在 C++中,一个重要的概念是保留的关键字 this。在类中,关键字 this 包含当前对象的地址,换句话说,其值为&object。当您在类成员方法中调用其他成员方法时,编译器将隐式地传递 this 指针———数调用中不可见的参数:
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”)。
  从编程的角度看,this 的用途不多,且大多数情况下都是可选的。例如,在程序清单 9.2 中,可将SetAge( )中访问 age 的代码修改成下面这样:
void SetAge(int humansAge)
{ this->age = humansAge; // same as age = humansAge
}

将 sizeof( )用于类

  您知道,通过使用关键字 class 声明自定义类型,可封装数据属性和使用数据的方法。第 3 章介绍过,运算符 sizeof( )用于确定指定类型需要多少内存,单位为字节。这个运算符也可用于类,在这种情况下,它将指出类声明中所有数据属性占用的总内存量,单位为字节。sizeof( )可能对某些属性进行填充,使其与字边界对齐,也可能不这样做,这取决于您使用的编译器。

结构和类的不同之处:

关键字 struct 来自 C 语言,在 C++编译器看来,它与类及其相似,差别在于程序员未指定时,默
认的访问限定符(public 和 private)不同。因此,除非指定了,否则结构中的成员默认为公有的(而类成员默认为私有的);另外,除非指定了,否则结构以公有方式继承基结构(而类为私有继承)

Human的struct实现:

struct Human
{ // constructor, public by default (as no access specified is mentioned) Human(const MyString& humansName, int humansAge, bool humansGender) : name(humansName), age (humansAge), Gender(humansGender) {}int GetAge () { return age; }
private: int age; bool gender; MyString name;
};
正如您看到的,结构 Human 与类 Human 很像;结构的实例化与类的实例化也很像:
Human firstMan("Adam", 25, true); // an instance of struct Human

声明友元

不能从外部访问类的私有数据成员和方法,但这条规则不适用于友元类和友元函数。要声明友元
类或友元函数,可使用关键字 friend

样例代码:

#include<iostream>
#include<string>
using namespace std;class Human {private:friend class Utility;int age;//init 0string name;public:Human(string humansName = "Adam", int humansAge = 25): name(humansName), age(humansAge) {
//      name=humansName;
//      age=humansAge;}
};class Utility {public:static void DisplayAge(const Human& person) {cout << person.age << endl;}
};int main(void) {Human firstMan("Adam", 25);cout << "Accessing private member age via friend class: ";Utility::DisplayAge(firstMan);//Utility这个类没有对象,所以我们直接使用它的DisplayAge函数return 0;
}

friend class Utility;

指出 Utility 类是 Human 类的友元,该声明让 Utility 类的所有方法都能访问 Human 类的私
有数据成员和方法。

共用体:一种特殊的数据存储机制

共用体是一种特殊的类,每次只有一个非静态数据成员处于活动状态。因此,共用体与类一样,可包含多个数据成员,但不同的是只能使用其中的一个

1.声明共用体

union UnionName
{ Type1 member1; Type2 member2;
…TypeN memberN;
};

实例化:

UnionName unionObject;
unionObject.member2 = value; // choose member2 as the active member

与结构类似,共用体的成员默认也是公有的,但不同的是,共用体不能继承。
另外,将 sizeof()用于共用体时,结果总是为共用体最大成员的长度,即便该成员并不处
于活动状态。

2.何时使用共用体:

  在结构中,常使用共用体来模拟复杂的数据类型。共用体可将固定的内存空间解释为另一种类型,有些实现利用这一点进行类型转换或重新解释内存,但这种做法存在争议,而且可采用其他替代方式。

enum和switch-case一起用。

对类和结构使用聚合初始化

例1:

int myNums[] = { 9, 5, -1 }; // myNums is int[3]
char hello[6] = { 'h', 'e', 'l', 'l', 'o', ' \0' };
然而,并非只有由整数或字符等简单类型组成的数组属于聚合类型,类(以及结构和共用体)也
可能属于聚合类型。有关结构和类的规范标准指出了结构和类必须满足什么条件才属于聚合类型,但在不同的 C++标准中,需要满足的条件存在细微的差别,但完全可以这样说,即满足如下条件的类或结构为聚合类型,可作为一个整体进行初始化:只包含公有和非静态数据成员,而不包含私有或受保护的数据成员;不包含任何虚成员函数;只涉及公有继承(不涉及私有、受保护和虚拟继承);不包含用户定义的构造函数。

例2:

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}};
问:总是应该编写一个复制构造函数吗?
答:如果类的数据成员是设计良好的智能指针、字符串类或 STL 容器(如 std::vector),则编译器
生成的默认复制构造函数将调用成员的复制构造函数。然而,如果类包含原始指针成员(如使用 int*
而不是 std::vector<int>表示的动态数组),则需要提供设计良好的复制构造函数,确保将类对象按值传
递给函数时进行深复制,创建该数组的拷贝。
问:在复制构造函数中,为何将指向源对象的引用作为参数?
答:这是编译器对复制构造函数的要求。其原因是,如果按值接受源对象,复制构造函数将调用
自己,导致没完没了的复制循环。

今天结束了,寄几寄~~~

C++学习 Day.5(进入正轨~~)相关推荐

  1. 每周更新学习进度表--第九周

    每周更新学习进度表:   学习时间 新增代码行 博客量(篇) 知识总结 第一周  7h  80  2  对于软件工程这门课有个大致的了解,并在学习代码上步入正轨. 第二周  8h  100  4  四 ...

  2. 我们如何学习:学会学习再学习

    我们如何学习:学会学习再学习 学习方法:不同科目不同方法 人和人学习能力的差距在哪里? 快速学习:我不是会得多,只是学得快 学习动力:培养啥耐心呀,你真的有欲望要做的事,八头牛都拉不住你 激发好奇心: ...

  3. 我与我的专业计算机作文500字,我的学习生活作文500字(通用5篇)

    我的学习生活作文500字(通用5篇) 导语:在日常学习.工作抑或是生活中,大家都尝试过写作文吧,作文要求篇章结构完整,一定要避免无结尾作文的出现.还是对作文一筹莫展吗?下面是小编为大家整理的我的学习生 ...

  4. 从凡人到筑基期的单片机学习之路

    为防止读者误解,首先申明一点,我不是大佬,亦不是大神,只是众多单片机学习者中的一员而已.我写此文的目的主要是记录自己学习的过程,并借此为一些初学者提供部分参考,或许能让初学者少走一些弯路. 从小我对电 ...

  5. 英文学习法—-林语堂

    1.目标 英文是活的语言,现代通用的语言.凡是学习英文的人务必认定这个目标,学习现代通行活用的英语.这个目标认定,方法才不会错误.若把英文看作死的,固定的语言,将来对于文法,读物,发音都要偏重于迂腐的 ...

  6. 第一次罗塞塔学习---收获总结

    前言 感觉学习罗塞塔用了好长好长的时间啊,怎么就一直都点不完啊,刚开始看其他师哥师姐点的时候感觉这个东西真好玩,怎么到了自己点的时候,就感觉,天呢,这是我之前认识的罗塞塔嘛! 过程中 其实在点罗塞塔的 ...

  7. 期末总结---为本学期画上圆满的句号

    期末总结---为本学期画上圆满的句号 记得开学第一节课,我们都对算法结构感到很疑惑,不知道这门课程是学什么的,直到第一节课,我们见到了老贺(感觉这样叫比较亲切),老师给我们详细的介绍了我们这节课主要学 ...

  8. 2w学费买来的英语学习方法

    目录快速浏览: 1.培训机构的背后 2.那些恐怖的经历 3.对英语教学的质疑 4.重新思考,找到自我 1. 培训机构的背后 说起英语培训机构,当你百度一下时,发现全是各种黑,现在的英语培训机构几乎没有 ...

  9. 从校园到职场,谈谈我的转变

    本文原发表地址:从校园到职场,谈谈我的转变 一.大学时光 时间回到2014年9月,从高中进入大学.这是我的第一次转变,尽管当时我不这么认为也意识不到这个转变.印象最为深刻的还是入学那一段时间,现在我都 ...

最新文章

  1. 面对大规模AI集成,企业为何迟迟犹豫?
  2. python的concat用法_Pandas串联操作concat()用法介绍
  3. 攻防世界-web-i-got-id-200-从0到1的解题历程writeup
  4. Android协程学习
  5. 打不开磁盘配额linux,九度OJ 1455 珍惜现在,感恩生活 -- 动态规划(背包问题)...
  6. anaconda安装python视频_怎么安装anaconda?
  7. 12-order by和group by 原理和优化 sort by 倒叙
  8. Pytorch —— 优化器Optimizer(二)
  9. vue2.0 + vux (六)NewsList 资讯页 及 NewsDetail 资讯详情页
  10. 如何在linux中也能够使用自动类型推导关键字auto?
  11. dtu连接mysql_数据中心使用dtu远程连接oracel 9i数据库问题
  12. 一维码二维码识别(opencv c++)
  13. OpenWrt设置路由器联网(无线)
  14. Telegram Download Default Chat Wallpaper
  15. 严寒冰 国家计算机网络,北京航空航天大学计算机学院——严寒冰
  16. flutter检测网络状态
  17. r语言c函数怎么用,R语言学习笔记——C#中如何使用R语言setwd()函数
  18. java.sql.SQLException: The server time zone value '???ú±ê×??±??' is unrecognized or represents 解决方法
  19. UVA10765 Doves and bombs(双连通分量)
  20. ad频谱分析 matlab_MATLAB信号频谱分析FFT详解

热门文章

  1. 如何使用DMA,包含源码以及详细注释
  2. mysql创建用户只能访问数据库中一张表
  3. html 设置图片左对齐,CSS设置图片的对齐
  4. 玩游戏掉帧严重?看过来!
  5. 铁路售票处实习记:买火车票须知
  6. 微信开发工具控制台报错 未找到入口 app.json文件?
  7. React 源码系列 | React Context 详解
  8. 平移计算机图形学代码注释,求代码注释:计算机图形学的OpenGL画四面体。高手来吧。争取每句都注释下。谢谢...
  9. MAC OS下设置bits/stdc++.h万能头文件
  10. 2022年Work-Life Balance能实现吗?