对象:现实中对象的模拟,具有属性和行为。
类:同一类对象的共同属性和行为。
对象是类的实例,
同一类对象的共同属性和行为进行抽象形成了类。
类将数据和处理数据的函数封装在一起,隐藏细节提供对外接口,编译对象时,我们需要用构造函数对对象进行初始化。删除对象的时候,通过析构函数对对象占用的资源进行释放。
定义类的时候我们还可以使用已经有的类的对象作为新类的成员进行组合。
类的基本特点:
抽象:对同一类对象的共同属性和行为进行概括,形成类。
封装:将抽象出的数据,代码封装在一起,形成类。
多态:同一个名称在程序中有不同的功能实现方式。
继承:在已有类的基础上进行扩展形成新的类。
class Stock{//不写public则默认是私有的
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot(){total_val=shares*share_val;}
public://外部接口
void acquire(const std::string &co,long n,double pr);
};
对象的定义:
类名 对象名(Stock myStock;)在主函数中实现类,先要定义类的实例:Stock myStock,再对类的函数进行调用。
类中成员之间可以互相访问,用成员名就可以互相访问,从类外访问成员使用“对象名·成员名”访问public成员。
类的成员函数:
1.在类中声明函数原型;
2.在类外给出函数体实现,并在函数名前使用类名加以限定。
3.也可以直接在类中给出函数体,形成内联成员函数。
4.允许声明重载函数和带默认参数值的函数。
内联函数:
可以提高效率,所以不要包含复杂的结构。声明内联函数的方式:
1.函数体放在类的声明中
2.将函数定义放在类中,在类外使用inline关键字定义函数体
构造函数:Clock(int newH=0,intM=0,int newS=0);//再写了构造函数之后系统不会再自动生成默认的构造函数,此时需要我们自己手动加上构造函数,函数的重载。
1.类中的特殊函数
2.用于描述初始化算法
要求:
1.函数名与类名相同
2.不能定义返回值类型,也不能有return语句
3.可以有形参也可以没有
4.可以是内联函数
5.可以重载
6.可以带默认参数值
构造函数在对象创建时自动调用。
默认构造函数:
Clock();
隐含生成的构造函数:若程序未生成构造函数,则编译器会自动生成一个默认构造函数,参数列表为空不为数据成员设置初始值。
初始化列表:对类的成员列表进行初始化,将形参值赋值给类的对应项的数据成员
Clock::Clock(int newH,int newM,int newS)://调用有参数的构造函数
hour(newH),minute(newM),second(newS){
}
Clock::Clock():
hour(0),minute(0),second(0){//调用无参数的构造函数
}
构造函数的使用
Clock a1(0,0,0);//调用有参数的构造函数,也可以写成Clock a1=Clock(0,0,0);
Clock a2;//调用无参构造函数
委托构造函数:使用类的其他构造函数执行初始化过程,对于函数体相同的构造函数去复杂化,保证代码的一致性。
Clock(int newH,int newM,int newS):
hour(newH),minute(newM),second(newS){
}
Clock():Clock(0,0,0){}
//无参数的构造函数调用了有参数的构造函数,将三个默认初始化参数传给有参数表的构造函数。
复制构造函数:用已经存在的对象初始化新的对象,已经存在的
对象的引用作为构造函数的
参数。如果没有手动定义复制构造函数,编译器会自动生成一个默认复制构造函数,实现两个对象成员之间的一一对应。当构造函数中包含指针则默认的构造函数就不够用了。
调用复制构造函数的情况:
1.定义一个对象时,以本类另一个对象作为初始值,发生复制构造;
2.如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制;
3.如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象,传递给主调函数,此时发生复制构造。
Clock(int newH=0,int newM=0,int newS=0){}//构造函数
Clock(const Clock& p)=delete;//指示编译器不生成默认复制构造函数。
例子:
void fun1(point p){}//形参为point类对象的函数
Point fun2(){//返回值为Point类对象的函数
Point a;
return a;
}
Clock a;//生成一个对象a
Clock b(a);//用a初始化b,第一次调用拷贝构造函数
fun1(b);//用对象做实参去调用函数,函数的形参类型是类的对象,用形参去初始化实参也会发生一次复制构造
b=fun2();//函数的返回值是类对象,构造一个临时无名对象传给调用者,调用复制构造。
类的组合:
1.类中的成员是另一个类的对象。
2.可以在已有抽象的基础上实现更复杂的抽象。
用组合类构造函数将部件构造函数需要的参数传递给他,部件类的构造函数来初始化部件对象。
类组合的构造函数设计:
1.原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化。
#include
<iostream>
using
namespace
std;
class
Point
{
public
:
int
getX() {
return
x; }
int
getY() {
return
y; }
Point(
Point
&
p
);
Point(
int
a
,
int
b
);
private
:
int
x, y;
};
Point
::Point(
int
a
,
int
b
) {
x =
a
;
y =
b
;
}
Point
::Point(
Point
&
p
) {
//拷贝构造函数的实现。形实结合传参数时是从后面开始传入的所以一开始进去的是myp2。
x =
p
.x;
y =
p
.y;
cout
<<
"calling the copy constructor of Point"
<<
endl;
}
class
Line
{
public
:
Line(
Line
&
l
);
double
getLen() {
return
len; }
Line(
Point
xp1
,
Point
xp2
);
private
:
Point
p1, p2;
//p1在前先被初始化
double
len;
};
//组合类的构造函数
Line
::Line(
Point
xp1
,
Point
xp2
) :p1(
xp1
), p2(
xp2
) {
//先完成初始化列表,用形参xp1初始化当前线段的端点p1,用形参xp2初始化当前线段的端点p2。初始化顺序取决于定义的次序,在前的先被初始化
cout
<<
"calling constructor of line"
<<
endl;
double
x =
static_cast
<
double
>(p1.getX() - p2.getX());
double
y =
static_cast
<
double
>(p1.getY() - p2.getY());
len = sqrt(x*x + y*y);
}
//组合类的拷贝构造函数
Line
::Line(
Line
&
l
) :p1(
l
.p1), p2(
l
.p2) {
//用p1,p2初始化新的端点
cout
<<
"Calling the copy constructor of Line"
<<
endl;
len =
l
.len;
}
int
main() {
Point
myp1(1, 1), myp2(4, 5);
//建立Point类的对象
Line
line(myp1, myp2);
//建立line类的对象
Line
line2(line);
//利用拷贝构造函数建立一个新的对象
cout
<<
"the length of the line is:"
;
cout
<<
line.getLen()
<<
endl;
cout
<<
"the length of the line2 is:"
;
cout
<<
line2.getLen()
<<
endl;
getchar();
return
0;
}
构造组合类对象时的初始化次序:
首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,
初始化次序是成员在类体中定义的次序。
(1)成员对象构造函数调用顺序:按对象成员的定义顺序,先声明者先构造。
(2)初始化列表中为出现的成员对象,
调用默认构造函数(无形参)初始化。
处理完初始化列表后再执行构造函数的函数体。
//想要类通用,一定要记得写默认构造函数,因为当这个类的对象被用作其他类的部件时,可能组合类不写构造函数,需要部件对象有构造函数。
实现类成员函数:
void Stock::acquire(
const std::string &co,long n,double pr);
类内初始值,对数据进行初始化,和函数的形参初始化类似。
前向引用声明:希望在一个类中引用另一个类的函数参数类型,第二个类再引用第一个类,两个类之间的相互引用,因为在类的引用中,定义在前的类才能被引用。如果需要在某个类的声明之前,引用该类,则应进行前向引用声明。前向引用声明只为程序引入一个标识符,但具体声明在其他地方。
两个类互相引用的例子:
class B;
//前向引用声明
class A{
public:
void f(B b);//告诉参数列表B是一个类,所以在A中可以引用
};
class B{
public:
void g(A a);
};
前向引用声明注意事项:
(1)在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联对象函数中使用该类。
(2)当使用前向引用声明时,只能使用被声明的符号,不能涉及类的任何细节。
结构体和类的差异:
类中默认的是private,结构体重默认是public。
使用结构体的情况:主要用来保存数据,既可以是数据成员和函数成员。
联合体:
union关键词
特点:成员共用同一组内存单元,任何两个成员不会同时有效
例子:
union Mark{
char grade;
bool pass;//3个字节
int percent;//4个字节
};//成绩只有一种表现形式,内存的分配按照最大的分配
枚举类定义: 枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号隔开。
语法形式:
enum class 枚举类型名:底层类型{枚举值列表};//默认的底层类型为int
例:
enum class Type:char{General,Light,Medium,Heavy};
枚举类的优势:
(1)强作用域:将其作用域限制在枚举类中,避免不同的枚举类之间的枚举值的重名问题
如使用Type的枚举值General:Type::General
(2)转换限制:枚举类对象不可以与整型隐式地互相转换
(3)可以指定底层类型
类的静态成员:被类的所有对象所共用,在类中只是进行静态数据成员说明(如:static int count)初始化在类外。