文章目录
-
- 第25讲:类的定义
- 第26讲:对象的定义和使用
- 第27讲:构造函数
- 第28讲:默认构造函数和赋值构造函数
- 第29讲:析构函数
第25讲:类的定义
- C语言——面向过程的程序设计思想(自顶向下逐步求精;一个main函数外加若干子函数),C++——面向对象的程序设计思想(实现软件设计的产业化;自然界是由实体对象构成的)。
- 【抽象】:数据抽象、行为抽象。
- 【封装】:将抽象出的数据成员和行为成员聚合并视为一个整体——类(细节隐藏,接口开放)。
- 【继承与派生】:保持类原有特性的基础上,进行更具体的说明。
- 【类定义】:
class 类名{成员列表};
- 类可以没有成员,也可以有多个成员;类的成员可以是数据,也可以是函数;类的定义一旦完成后就无法再添加成员了。
- 类中成员函数的声明是必需的,但定义可在类外声明。
- 类成员的访问有两种来源:类成员和类用户。
- 类成员具有访问控制属性,分三种:
,public
,private
。protected
属性将类成员开放给类外部的用户访问(外部接口);public
属性将类成员限制为仅给类内成员可访问;private
属性将类成员限制为仅给类内成员可访问,此外该类的派生类的成员亦可访问。protected
class 类名{
public: // 公共成员
protected: // 保护成员
private: // 私有成员
};
- 类成员可为类对象。
- 【成员函数的声明与定义】:类外定义类成员函数的话,必须将类内的成员函数声明放在类定义的前面,否则编译出错。【将类成员函数的定义实现放在类体外有利于接口和实现的分离】
- 【成员函数的隐式内联】:类成员函数仅在定义置于类体外,且声明与定义均无
修饰的情况下为非内联函数。inline
- 【成员函数的重载与默认参数设置】:类成员函数的重载和默认参数的设置必须在类成员函数的第一次声明或定义的地方。
- 【成员函数的存储】:同一个成员函数的代码公用一段存储空间,即不重复存储副本。而且C++将类成员函数的代码存储在类对象之外的内存区域,故
计算类对象的大小时只计算出类对象的数据成员的大小总和。sizeof
- 一个源文件中同一个类不能重复定义;类的定义通常放在头文件中,由此可保证每个使用该类的文件都以同样的方式定义类。
- 【前向声明】:可以只声明一个类但不定义。此时不能定义该类的对象,只能用于定义指向该类的指针和引用,或者用于以此类为形参类型或返回值类型的函数的声明。
- 将类实例化之前必须已经确定类的定义,否则编译出错。类的成员不能是该类本身,否则因递归定义而无法确定该类。
第26讲:对象的定义和使用
- 类对象一般用动态内存分配。
- 【类成员的访问】:
;对象名.成员名
;对象指针->成员名
。对象引用.成员名
- 类对象之间可整体赋值。
- 类对象、类对象指针、类对象引用可作为函数参数及函数的返回值。
第27讲:构造函数
- 【构造函数】:定义类的时候并未产生类实体,因此未发生类成员的初始化。但是私有或者保护成员在类体外又无法初始化,因此构造函数是必须的。构造函数在类实体化时自动地被系统调用,以此达到给类对象初始化的目的。
- 【定义构造函数】:C++规定构造函数的名字与类的名字相同,一般在类内声明而在类体外定义,且不能指定返回类型,形参可有可无,此外构造函数可声明为内联的。
- 构造函数是在创建对象时自动执行的,且只执行一次,此外还不能人为调用;构造函数一般声明为
,否则只能在类内部创建对象并初始化,这不是通常的做法;构造函数应该为每个数据成员初始化,且不应加入与初始化无关的内容;带参构造函数在初始化时传入不同的参数即可进行不同的初始化。public
#include<iostream>
#include<stdio.h>
using namespace std;
class Cuboid {
public:
Cuboid(int l, int h, int d);
int volume() {
return length*height*depth;
}
private:
int length, height, depth;
};
Cuboid::Cuboid(int l, int h, int d) {
// 一般长的构造函数定义放在类外实现
length = l;
height = h;
depth = d;
cout<<"length,height,depth="<<l<<","<<h<<','<<d<<endl;
}
int main() {
Cuboid a(1, 2, 3);
cout<<"Volume="<<a.volume()<<endl;
Cuboid b(10, 20, 30);
cout<<"Volume="<<b.volume()<<endl;
return 0;
}
- 【构造函数的初始化列表】:与其他函数不同的是,构造函数可有初始化列表。
类名(形式参数列表):初始化阶段{
普通计算阶段
}
第28讲:默认构造函数和赋值构造函数
- 有时候(成员类没有默认构造函数、成员为引用类型、成员为
型)必须提供类构造函数的初始化列表。如果另一个类定义时直到调用其成员类的默认构造函数都失败,则编译出错。const
class Point{
private:
int x; // 同类项的成员变量不能一起定义?
int y;
public:
Point(int i, int j){ // 无默认构造函数
x = i, y = j;
}
void print(){cout<<x<<","<<y<<endl;}
};
class pointTest{
private:
point a; // 成员为类对象,能不能在此处给出成员类a的参数?在此无法接受构造函数的实参
public:
pointTest(int i, int j):a(i, j){} // 只能在构造函数参数列表里对成员a初始化
};
- 【成员初始化次序】:按数据成员的声明顺序,所以应该避免使用成员初始化成员。
- 【构造函数的重载】:构造函数允许重载,以此达到以不同的方式初始化类数据成员的目的。
class Point{
public:
Point(){x=y=0;} // 无参数的构造函数
Point(int a, int b):x(a),y(b){} // 有参数的构造函数
// 可为构造函数设置默认参数,但默认参数的设置必须放在类体内
// 且构造函数有重载的情况下,要避免默认构造与默认值构造之间的歧义
void display(){cout<<x<<","<<y<<endl;}
private:
int x, y;
};
int main(){
Point m;
m.display();
Point n(1, 2);
n.display();
return 0;
}
第29讲:析构函数
- 【析构函数】:清理所创建对象占用的内存空间。编译器总是为一个类合成一个析构函数,但要删除指针成员所指的对象必须显式地编写析构函数。程序执行到对象作用域结束处时触发对象的析构函数;
分配的对象被new
时触发对象的析构函数。delete
- 许多类不需要编写析构函数,尤其是有构造函数的类。析构函数通常用于释放类在生命周期中获取的资源。
- 【析构函数三法则】:显式析构函数的编写一般出现在复制构造函数为显式和赋值运算符重载的情况下。
- 先构造的后析构。