目录
类和对象(一)
1. 类的构成
- 类名
- 数据成员
- 成员函数
2. 类成员的三种访问属性
访问属性 | 属性名 | 使用范围 |
---|---|---|
公有类型 | public | 可以由程序中的函数访问 |
保护类型 | protected | 可以由本类和本类的派生类访问 |
私有类型 | private | 只能由本类的成员函数访问 |
- 默认情况下,类体中没有访问关键词时,类中的成员默认为私有的
- 数据成员可以是任意数据类型,但是不可以是自动类型
- 不能在类的声明当中给数据成员赋初值
private:
int year = 2018;//错误,不可以在声明中进行赋值;
- struct和class声明的类的区别
- 默认访问属性不同: 前者默认是public,后者默认是private
- 类更好的体现了面向程序设计中封装与信息隐藏的特点
3. 类的成员函数
成员函数的定义方式
- 将成员函数直接定义在类体中
public:
void method1(){
cout<<"在类体中直接定义成员函数";
}
- 在类定义中给出成员函数的原型,函数体写在类的定义之外
返回值类型 函数名(参数列表);
返回值类型 类名:: 函数名(参数列表){}
class study
{
public:
void method2(int,int);//函数原型
};
void study::method2(int a, int b)//函数的实现
{
x = a;
y = b;
}
- 显示声明函数的内联函数
- inline 返回类型 类名 :: 成员函数名(参数表){函数体}
- 使用inline说明内联函数时,必须使用函数体和inline说明结合在一起,否则编译器将它作为普通函数处理
4. 对象的定义
- 在声明的同时直接定义对象
class point{
}op1,op2;
- 声明了类之后在使用时定义对象
point op1,op2;//类名 对象名;
5. 对象中成员的访问
- 圆点访问形式: 对象名.成员名 || (*指向对象的指针).成员名
- 指针访问形式: 对象指针变量名 -> 成员名 || (&对象名)->成员名
class calendar{
int day;
int month;
int year;
};
int main(){
calender c1;
calender *c2 = new calender;
//圆点访问形式
cout << c1.year << endl;
cout << (*c2).year << endl;
//指针访问形式
cout << c2->year << endl;
cout << (&c2)->year << endl;
}
6. 构造函数
- 构造函数是与类名同名的特殊的成员函数,当定义该类的函数时,构造函数被系统自动调用,以实现对对象的初始化.
- 构造函数必须和类名同名,以类名为函数名的函数一定是类的构造函数
- 构造函数没有返回值类型,但是有隐含的返回值,该值由系统内部使用
- 可以有不同类型的参数
- 构造函数是特殊的成员函数,函数体可以写在类体内,也可以写在类体外
- 构造函数可以重载,一个类中可以定义多个参数个数或者参数类型不同的构造函数
- 构造函数被声明为公有函数,但他不能显示调用,他在定义对象的同时被系统自动调用
[对比理解: 说白了C++的构造函数综合了java中的无参和有参构造函数,通过重载实现了各种形式的有参构造函数] - 构造函数的作用说白了就是实现数据成员的初始化
7. 析构函数
- 析构函数也是一种特殊的成员函数,和构造函数的作用相反,通常用于撤销一些清理任务,比如释放分配给对象的内存空间
- 析构函数的名称: ~类名
- 析构函数没有返回类型和参数,不能够随意调用,没有重载,也是由系统自动调用
- 一般系统会自动创建一个析构函数,但是如果对象中由动态分配的内存时,需要显示的为该类提供适当的析构函数,以完成清理工作
- 一个中只能有一个析构函数
- 对象被析构的顺序和建立时的顺序相反,最后被构造的对象最先被析构
- 调用析构函数的情况:
- 当一个对象被定义在一个函数体内时,在这个函数体结束的时候对象的析构函数会被自动调用
- 当一个对象使用new运算符动态创建,在使用delete运算符释放它时,delete会自动调用析构函数
8. 重载构造函数
- 参数个数或者类型不同实现重载
9. 拷贝构造函数
- 拷贝构造函数也是类的一个重载版本的构造函数,是一种特殊的构造函数,其形参是对本类对象的引用
- 拷贝构造函数的功能是用于实现对象值的拷贝.通过将一个同类对象的值拷贝给一个新对象而完成新对象的初始化,即用一个对对象去构造另外一个对象
- 拷贝构造函数的特点:
- 函数只有一个参数,并且是同类对象的引用
- 每一个类都必须有一个拷贝构造函数,一般情况下,系统会自动生成一个默认的拷贝构造函数
- 拷贝构造函数被系统自动调用的情况
- 由一个对象初始化另外一个对象时
- 当对象作为函数的实际参数传递给函数的值形式参数时
- 当对象作为函数返回值时
综合使用
析构函数的辨析
源代码
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "constructing A" << endl;
}
~A()
{
cout << "destructing A" << endl;
}
private:
int a;
};
class C
{
public:
C()
{
cout << "constructing C" << endl;
}
~C()
{
cout << "destructing C" << endl;
}
private:
int c;
};
class B : public A
{
public:
B()
{
cout << "constructing B" << endl;
}
~B()
{
cout << "destructing B" << endl;
}
private:
int b;
C c;
};
void main()
{
B b;
}
运行结果
constructing A
constructing C
constructing B
destructing B
destructing C
destructing A
#include<iostream>
using namespace std;
class Date {
private:
int year, month, day;
public:
Date(int y = 2009, int m = 1,int d = 1); //带有参数的构造函数
Date(const Date &date); //拷贝构造函数声明,形参是对象
//析构函数定义
~Date()
{
cout << "调用析构函数..." << endl;
}
void showDate();
};
Date::Date(int y, int m, int d)//构造函数定义
{
year = y;
month = m;
day = d;
cout << " 调用构造函数..." << endl;
}
Date::Date(const Date& date1)//拷贝构造函数的定义
{
year = date1.year;
month = date1.month;
day = date1.day;
cout << "调用复制构造函数..." << endl;
}
void Date::showDate()//输出函数定义
{
cout << year << "." << month << "." << day << endl;
}
Date Fun(Date date2)
{
Date date3(date2);
return date3;
}
int main()
{
Date o1(1999, 3, 20);//调用带参构造方法
Date o3;//调用构造方法,使用默认参数值
Date o2(o1);//调用拷贝构造函数
Date o4 = o2;//调用拷贝构造函数
o3 = o2;//调用拷贝构造函数
o3 = Fun(o2);//Fun函数内部创建date3时调用一次拷贝构造函数,对象作为返回值返回时调用一次构造函数
o3.showDate();//输出函数输出对象的值
return 0;
}
10. 浅拷贝和深拷贝
- 浅拷贝: 就是由默认的拷贝构造函数所实现的数据成员逐一复制(若类中含有指针类型的数据,这种按数据成员逐一赋值的方法将会产生错误
- 深拷贝: 不是复制指针本身,而是复制指针所指向的动态空间中的内容.实现了两个对象的指针成员拥有不同的地址值,指向不同的动态存储空间首地址,而且两个动态空间中的内容完全一样
两者的区别和联系
- 两者都是实现复制
- 在不涉及指针的拷贝时两者没有差别
- 深拷贝重新分配了空间,改变被拷贝对象时拷贝对象不会改变
内存泄漏
- 当实现浅拷贝时,只是将被拷贝对象的地址复制给了拷贝对象,两个对象指向同一个空间,并没有创建新的空间给新的对象,在调用析构函数清除空间时,同一个空间被清除两次,在第二次清除的时候,析构对象找不到释放的空间,就会产生内存泄漏.
class Test
{
private:
int* p;
public:
Test(int x)
{
this->p=new int(x);
cout << "对象被创建" << endl;
}
~Test()
{
if (p != NULL)
{
delete p;
}
cout << "对象被释放" << endl;
}
int getX() { return *p; }
//深拷贝(拷贝构造函数)
Test(const Test& a)
{
this->p = new int(*a.p);
cout << "对象被创建" << endl;
}
//浅拷贝(拷贝构造函数)
//Test(const Test& a)
//{
// this->p = a.p;
// cout << "对象被创建" << endl;
//}
};
int main()
{
Test a(10);
//我们手动的写拷贝构造函数,C++编译器会调用我们手动写的
Test b = a;
return 0;
}
11. UML(Unifined Modeling Language)统一建模语言
11.1 UML类型
- 类图,顺序图,协作图,类图,对象图,状态图,活动图,构件图和部署图
11.2 类图
- 类图是由类和与之相关的各种静态关系共同组成的图形
- 类图展示是软件模型的静态结构,类的们内部结构和其他类之间的关系
- 类图中最基本的是图形化描述类,要表示类的名称,数据成员和成员函数以及各成员的访问控制属性
11.3 类和对象
- 类名写在顶部区域
- 数据成员: 在中间区域
- 访问控制属性: public “+”, private “-”,protected “#”
- 名称: 是标识数据成员的字符串
- 类型:表述数据成员的类型
- 默认值: 赋予该数据成员的初始值
- 约束特征: 用户对该数据成员性质的约束说明
- 成员函数: 在底部区域
- 访问属性
- 名称
- 参数表
- 返回类型
- 约束特性