第3章 Class and Object

news/2025/2/23 5:04:46/

构造函数

Guaranteed initialization with the constructor使用构造函数保证初始化

• If a class has a constructor, the compiler  automatically calls that constructor at the  point an object is created, before client  programmers can get their hands on the  object. 

• The name of the constructor is the same as  the name of the class.

构造函数:

1、没有返回类型

2、会被自动调用

Constructors with arguments有参构造函数

• The constructor can have arguments to allow  you to specify how an object is created, give it  initialization values, and so on.

Tree(int i) {…}
Tree t(12);

Constructor1.cpp

struct X{int i;X(int i);void prt();
};
X::X(int i){this -> i = i;
}
X::prt(){cout << i << endl;
}
int main(){X a; //无参构造,相当于a.X()X a(1);//有参构造,相当于a.X(1)X a=1; //变量初始化,相当于X a(1)int m(10);// 相当于 m = 1;a.prt();
}

想要i的值固定

struct X{int i = 100;X();void prt();
};
//X::X(){
//  i = 100;
//}
X::prt(){cout << i << endl;
}
int main(){X a; //无参构造,相当于a.X()a.prt();
}//C++11会后才有这个特性:在成员变量定义的时候给初始值
//也可以采用构造函数的方式给成员变量赋初始值
X::X(){i = 100;
}

default意思:缺省;默认

缺省构造函数:没有参数的构造函数,可以是程序员定义的或者程序员没写时编译器提供的

普通构造函数:有参数的构造函数 X(int i);

如果没有无参构造函数,只有有参构造函数,则创建对象需要传入有参构造函数的参数

struct X{int i = 100;X(int i);void prt();
};
X::X(int i){this -> i = i;
}
X::prt(){cout << i << endl;
}
int main(){X a; //会报错X a(1);//需要传入参数a.prt();
}

如果没有定义有参构造函数,创建对象时就不能加参数

struct X{int i = 100;X();void prt();
};
X::X(){i = 100;
}
X::prt(){cout << i << endl;
}
int main(){X a; //正确X a(1);//会报错a.prt();
}
int main(){X b[10];//每个数组元素的i值为100//如果想给数组元素对象的成员变量赋值X b[10](7)//不对X b[10] ={1,2,3,4,5}//不对,因为只提供了5个值,数组元素一共有十个
}

The default constructor默认构造函数

• A default constructor is one that can be called with 

no arguments.

struct Y {float f; int i; Y(int a); 
};
Y y1[] = { Y(1), Y(2), Y(3) }; //OK,每个元素类型都是Y,没有给大小,根据大括号内动态决定
Y y2[2] = { Y(1) };//错误,大括号内只有一个,要有两个
Y y3[7];//不行,结构体内含有参构造函数,创建对象就必须传入参数
Y y4;//不行,因为结构体内含有参构造函数,创建对象就必须传入参数

“auto” default constructor

• If you have a constructor, the compiler ensures  that construction always happens.

• If (and only if) there are no constructors for a  class (struct or class), the compiler will  automatically create one for you.

The destructor析构函数

• In C++, cleanup is as important as initialization and is  therefore guaranteed with the destructor.

• The destructor is named after the name of the class 

with a leading tilde (~). The destructor never has any 

arguments.

struct Y { public: ~Y(); 
};
struct X{X(int i);void prt();~X();
};
X::X(int i){this -> i = i;
}
X::prt(){cout << i << endl;
}
X::~X(){cout << "~X()" << i << endl;
}
int main(){X a(7); X b(11);a.prt();b.prt();
}
/*
输出:
7
11
~X()11 // b的析构
~X()7 // a的析构
*/

先构造的后析构,因为可能后面的对象会用到前面的对象,所以先构造的不能先析构。

//代码复杂一些
int main(){X a(7); {X b(11);}a.prt();//b.prt();
}
/*
输出:
~X()11 //b被析构,因为出了大括号这个生存期
7
~X()7 // a的析构
*/

说明析构发生在离开大括号的时候

Storage allocation

• The compiler allocates all the storage for a  scope at the opening brace of that scope. 

• The constructor call doesn’t happen until the sequence point where the object is defined.

Examlpe: Nojump.cpp

class X{private:char* buf;public:X(){buf = new char[1024];};~X(){delete buf;}
}
X::X(){}
void f(int i){if(i < 10){goto jump1;}X x1;jump1;switch(i){case 1:X x2;break;case 2:X x3;break;}
}
/*
如果i小于10,goto跳转到jump1,一旦进入到f函数,本地变量就被分配了空间,
但是此时x1的构造函数不会执行,程序结束时,由于析构函数找不到要delete的buf 
同理,switch的大括号规定了x2和x3的生命周期,一旦进入就给他们分配了空间,但由于case,x2或x3可能不会在对应的case下执行构造函数,最后析构的时候也会有问题。
解决方法:
1、不用goto
2、不用switch
*/

Aggregate initialization聚合体初始化

• int a[5] = { 1, 2, 3, 4, 5 }; 
• int b[6] = {5}; 
• int c[] = { 1, 2, 3, 4 }; 
– sizeof c / sizeof *c
• struct X { int i; float f; char c; }; 
– X x1 = { 1, 2.2, 'c' }; 
• X x2[3] = { {1, 1.1, 'a'}, {2, 2.2, 'b'} }; 
• struct Y { float f; int i; Y(int a); }; 
• Y y1[] = { Y(1), Y(2), Y(3) };

Defifinition of a class

• In C++, separated .h and .cpp files are used to define  one class.

• Class declaration and prototypes in that class are in  the header file (.h).

• All the bodies of these functions are in the source  file (.cpp).

compile unit

• The compiler sees only one .cpp file, and  generates .obj file。一个.cpp文件是一个编译单元,编译器在编译的时候只看见这一个.cpp文件

• The linker links all .obj into one executable  file

• To provide information about functions in  other .cpp files, use .h

The header fifiles

• If a function is declared in a header file, you  must include the header file everywhere the  function is used and where the function is  defined.

• If a class is declared in a header file, you must  include the header file everywhere the class is  used and where class member functions are  defined.

Header = interface

• The header is a contract (契约)between you and the 

user of your code. 

• The compile enforces the contract by  requiring you to declare all structures and  functions before they

Structure of C++ program

Declarations vs Defifinitions

• A .cpp file is a compile unit

• Only declarations are allowed to be in .h

• extern variables

• function prototypes

• class/struct declaration

#include

• #include is to insert the included file into  the .cpp file at where the #include statement  is.

• #include “xx.h”:first search in the current  directory, then the directories declared  somewhere

• #include <xx.h>:search in the specified  directories

• #include <xx>:same as #include <xx.h>

Standard header fifile structure

防止多次声明

#ifndef HEADER_FLAG 
#define HEADER_FLAG // Type declaration here...
#endif // HEADER_FLAG

Tips for header

1. One class declaration per header file

2. Associated with one source file in the same 

prefix of file name.

3. The contents of a header file is surrounded  with #ifndef #define #endif

Clock display

Abstract

• Abstraction is the ability to ignore details of  parts to focus attention on a higher level of a  problem.

• Modularization is the process of dividing a  whole into well-defined parts, which can be  built and examined separately, and which  interact in well-defined ways.

Modularizing the clock display

NumberDisplay.h

#ifndef __NUMBER_DISPLAY__
#define __NUMBER_DISPLAY__struct NumberDisplay{int value = 0;int limit = 0; //上界NumberDisPlay(int limit);int setValue(int value);int getValue();bool increase();
};#endif

NumberDisplay.cpp

#include "NumberDisplay.h"NumberDisplay::NumberDisPlay(int limit){this -> limit = limit;  
}void NumberDisPlay::setValue(int value){this -> value = value;
}int NumberDisPlay::getvalue(){return value;
}bool NumberDisPlay::increase(){value++;if(value == limit){value = 0; //当值达到上限时,重新置零return true;}return false;
}

main.cpp

#include <iostream>
#include "NumberDisPlay"
using namespace std;int main(){NumberDisPlay n(10);n.setValue(2);for(int i = 0; i < 15; i++){if(n.increase()){cout << "-------------" << endl;}cout << n.getValue() << endl;}return 0;
}
/*
输出:
3
4
5
6
7
8
9
------------------
0
1
2
3
4
5
6
7
*/

Clock.h

#ifndef __CLOCK_H__
#define __CLOCK_H__#include "NumberDisPlay.h"struct Clock{// NumberDisplay hour(24);编译会报错// NumberDisplay minute(60);//类内初始值只能放在花括号里,或放在等号右边,记住不能使用圆括号NumberDisplay hour=24;NumberDisplay minute=60;void dida();int getTime()
}#endif

Clock.cpp

#include "Clock.h"void Clock::dida(){if(minute.increase()){hour.increase();}  
}int Clock::getTime(){return hour.getValue() *100 + minute.getValue(); 
}

main.cpp

#include <iostream>
#include "NumberDisPlay"
#include "Clock.h"using namespace std;int main(){// NumberDisPlay n(10);// n.setValue(2);// for(int i = 0; i < 15; i++){//   if(n.increase()){//     cout << "-------------" << endl;//   }//   cout << n.getValue() << endl;// }Clock clk;for(int i = 0; i < 123; i++){clk.dida();cout << clk.getTime() << endl;}return 0;
}

类内初始值只能放在花括号里,或放在等号右边,记住不能使用圆括号。

类外部创建对象时可以用圆括号,表示使用有参构造函数。


http://www.ppmy.cn/news/96842.html

相关文章

Unity之2D碰撞器

1、什么是碰撞器 碰撞器是用于在物理系统中 表示物体体积的的&#xff08;形状或范围&#xff09; 刚体通过得到碰撞器的范围信息进行计算 判断两个物体的范围是否接触 如果接触 刚体就会模拟力的效果产生速度和旋转 2、参数 Edit Collider&#xff1a;编辑碰撞器 Material…

JavaScript标准库函数解析

1. Object对象 1.1 init <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widt…

Entity Framework Core 简明教程(3)- 关系处理

在数据库层面&#xff0c;表之间关系&#xff0c;通过主键、外键来实现&#xff0c;基于约束 (constraint) 和数据完整性来制约。 在 EF Core 技术层面&#xff0c;并不是简单地与数据库这些关系和约束对应&#xff0c;EF Core 有它自己的机制。本篇介绍 EF core 在处理表关系方…

【Java系列】深入解析Java多线程

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级重要蓝色&#xff1a;用来标记二级重要 希望这篇文章能让你不仅有一定的收获&#xf…

【AIGC使用教程】Microsoft Edge/Bing Chat 注册使用完全指南

欢迎关注【AIGC使用教程】 专栏 【AIGC使用教程】SciSpace 论文阅读神器 【AIGC使用教程】Microsoft Edge/Bing Chat 注册使用完全指南 【AIGC使用教程】GitHub Copilot 免费注册及在 VS Code 中的安装使用 【AIGC使用教程】GitHub Copilot 免费注册及在 PyCharm 中的安装使用 …

PAT A1150 Travelling Salesman Problem

1150 Travelling Salesman Problem 分数 25 作者 CHEN, Yue 单位 浙江大学 The "travelling salesman problem" asks the following question: "Given a list of cities and the distances between each pair of cities, what is the shortest possible rou…

《Spring Guides系列学习》guide66 - guide68及小结

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gui…

CentOS7配置FRPS实现内网穿透

介绍 FRP&#xff08;Fast Reverse Proxy&#xff09;是一个用于进行内网穿透的工具&#xff0c;可以方便地将本地网络服务映射到公网上。本文将指导您在CentOS 7上安装和配置FRPS&#xff0c;以便您能够实现内网穿透。 步骤一&#xff1a;下载并上传FRPS程序包 首先&#x…