1、面向对象设计的主要特点:抽象、封装、继承、多态
2、一般来讲,对一个问题的抽象应该包括数据抽象(属性或状态)和行为抽象(对象的共同行为或功能特征)
3、封装:将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的函数代码进行有机的结合,形成“类”,其中数据和函数都是类的成员
多态性是指一段程序能够处理多种类型对象的能力
时钟类的定义:
class Clock
{
public:
void setTime(int newH,int newM,int news);//行为,代码成员
void showTime();
private:
int hour, minute,second; //属性,数据成员
};
在类中可以只声明函数的原型,函数的实现(函数体)可以在类外定义
4、成员函数的实现具体实现写在类定义外)
返回值类型 类名::函数成员名(参数表)
{
函数体
}
void Clock::setTime (int newH,int newM,int newS){
hour=newH;
minute=newM;
second=newS;
}
void Clock::showTime(){
cout<<hour<<":"<<minute<<":"<<second<<endl;
}
5.内联函数的生命有两种方式:隐式声明(将函数体直接放在类体内)和显式声明
将时钟类的showTime()函数声明为内联函数,可以写作:
class Clock{
public:
void setTime(int newH,int newM,int newS);
void showTime(){
cout<<hour<<":"<<minute<<":"<<second<<endl;
}
}
为了保证类定义的简洁,可以采用关键字inline显式声明(在函数体实现时,在函数返回值类型前加上inline,类定义中不加入showTime的函数体)
inline void Clock::showTime(){
cout<<hour<<":"<<minute<<endl;
}
6、时钟类的完整程序
#include <iostream>
using namespace std;
//时钟类的定义
class Clock{
public:
void setTime (int newH=0,int newM=0,int newS=0);
void showTime():
private:
int hour, minute,second;
}:
//时钟类成员函数的具体实现
void Clock::setTime(int newH,int newM,int newS){
hour=newH;
minute=newM;
second=newS;
}
inline void Clock::showTime(){
cout<<hours<<":"<<minute<<":"<<second<<endl;
}
//主函数
int main(){
Clock myClock;
cout<<"First time set and putout:"<<endl;
myClock.setTime(); //设置时间为初始值
myClock.showTime()
cout<<"Second time set and output:"<<endl;
myClock.setTime(8,30,30);
myClock.showTime();
return 0;
}
7、构造函数:在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。
特性:函数名和类名相同,无返回值,通常被声明为公有函数,对象被创建的时候被自动调用。
默认构造函数:调用时无须提供参数的构造函数。对于一个普通的类来说,通常要定义自己的默认构造函数。
有时函数体为空的构造函数并非不做任何事情,因为它还要负责基类的构建和成员对象的构建
作为类的成员函数,构造函数可以直接访问类的所有数据成员,可以是内联函数,可以带有参数表,可以带有默认的形参值,也可以重载。
8.委托构造函数:使用它所属类的其他构造函数执行它自己的初始化过程,把自身的一些指责委托给其它构造函数
使用委托构造函数重写Clock类的构造函数,其形式为:
Clock(int newH,int newM,int newS){
hour=newH;
minute=newM;
second=newS;
}
Clock():Clock(0,0,0){}
9、复制构造函数:其形参是本类对象的引用,其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。
如果没有定义类的复制构造函数,系统就会在必要时自动生成一个隐含的复制构造函数,把初始值对象的每个数据成员的值都复制到新建立的对象中。
声明和实现复制构造函数的一般方法:
class 类名
{
public:
类名(形参表); //构造函数
类名(类名 &对象名); //复制构造函数
……
};
类名::类名(类名 &对象名)
{
函数体 //复制构造函数的实现
}
复制构造函数的例子:
class Point{
public:
Point(int xx=0,int yy=0){
x=xx;
y=yy;
}
Point(Point &p);
int getX(){return x;}
int getY(){return y;}
private:
int x,y;
};
Point::Point(Point &p){
x=p.x;
y=p.y;
}
只有把对象用值传递时,才会调用复制构造函数,如果是传递饮用,不会调用。
复制构造函数在以下三种情况会被调用:
用类的一个对象去初始化该类的另一个对象、函数的形参是类的对象且调用函数时形参与实参结合、函数返回值是类的对象且函数执行完成返回调用者时
10、析构函数:用来完成对象被删除前的一些清理工作,是在对象的生存期即将结束的时候被自动调用的,不接受任何参数(但可以是虚函数)
11、default和delete两个关键字可以用来简化构造函数的定义与使用
class MyStr{
public:
string s;
MyStr()=default; //默认合成的无参构造函数
MyStr(string_s):s(std::move(_S)){}; //有参构造函数
MyStr(MyStr &&str)=default; //删除复制构造函数
~MyStr()=default; //默认合成的析构函数
};
除析构函数外,用户都可以指定为delete删除掉
12、类的组合描述的就是一个类内嵌其它类的对象作为成员的情况,他们之间是一种包含与被包含的关系。 当创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象将被自动创建。 因此在创建对象时既要对本类的基本类型数据成员进行初始化,又要对内嵌对象成员进行初始化。
13、析构函数的调用执行顺序与构造函数正好相反(析构函数的函数体被执行完毕后,内嵌对象的析构函数被一一执行,这些内嵌对象的析构函数调用顺序与他们在组合类的定义中出现的次序恰好相反。)
如果要为组合类编写复制构造函数,则需要为内嵌成员对象的复制构造函数传递参数》
例如:假设C类中包含B类的对象b作为成员,C类的复制构造函数形式如下:
c::c(c &c1):b(c1.b){……}
14、前向引用声明:在使用一个类之前,必须首先定义该类,即在引用未定义的类之前,将该类的名字告诉编译器,如:class B;
15、结构体是一种特殊形态的类,也可以有自己的数据成员和函数成员,构造函数和析构函数。
和类的唯一区别在于,具有不同的默认访问控制属性。在类中,对于未制定访问属性的成员,其访问控制属性为私有类型,在结构体中,为公有类型。
在结构体中,如果把公有成员放在最前面,最前面的“public"可以省去。