1、类和对象的基础知识,如类的定义,访问限定符,面向对象封装性,对象的大小计算等等。
类的定义:类(Class)实际上是某种类型的对象变量和方法的原型.类是从一些具有相同属性或功能的具体实例中抽象出共有的一些属性。
类是一个新的数据类型,它和结构体有点相似,是由不同数据类型组成的集合体,但类要比结构体增加了操作数据的行为,这个行为就是函数,还有一个区别就是类内存在类成员访问的修饰限定符。
·class是定义类结构体的关键字,花括号内被称为类体或类空间
·类名是一个新的数据类型,通过类名可以声明对象
·类的成员有函数和数据两种类型
·花括号内是定义和声明类成员的地方,关键字public,private,protected是类成员的访问限定符
注意:定义类结构体和定义结构体时花括号后要有分号
定义一个简单的类
class Person //类名
{
public : //访问限定符
void Display () //成员函数
{
cout<<_name <<"-"<< _sex<<"-" <<_age<< endl;
}
public : //成员变量
char*_name;
char*_ sex;
int _age; // 年龄
};
void Test ()
{
Person p ; //将类先实例化
p._name = "jack";
p._age = 10;
p._sex = "男 ";
p.Display ();
Person* ptr = &p;
ptr->name="peter";
ptr->_age = 18;
ptr->Display ();
}
成员函数的声明和定义
在类内定义成员函数
class person
{
public:
void Display()
{
cout<<_name<<"-"<<_sex<<"-"<<age<<endl;
}
public:
char*_name;
char*_sex;
int _age;
};
类外定义成员函数
class person
{
public:
void Display()
{}
public:
char*_name;
char*_sex;
int _age;
};
person::void person Display()//类外定义需要加限定域
{
cout<<_name<<"-"<<_sex<<"-"<<age<<endl;
}
关于对象的大小计算,与结构体的内存对齐规则相同
·第一个成员在与结构体变量偏移量为0的地址处。
·其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 //对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
·VS中默认的值为8 gcc中的默认值为4
·结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
·如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体 的对齐数)的整数倍。
类内部的成员函数不计入对象大小之内,成员函数放在公共代码区
当成员函数为空时,其大小为1
*
2.四个默认成员函数及运算符重载相关知识
当我们在定义一个类的同时,系统会默认生成默认的六个成员函数,它们分别是构造函数,拷贝构造函数,析构函数,赋值操作符重载,取地址符重载,const修饰的取地址符重载
(1)构造函数
成员变量为私有的,要对它们进行初始化,必须用一个公有成员函数来进行。同时这个函数应该有且仅在定义对象时自动执行一次,这时 调用的函数称为构造函数(constructor) 。
构造函数是特殊的成员函数,其特征如下:·函数名与类名相同, 无返回值, 对象构造(对象实例化)时系统自动调用对应的构造函数。
·构造函数可以重载(一般选择在类内定义)
· 如果类定义中没有给出构造函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动 生成缺省的构造函数。
· 无参的构造函数和全缺省值的构造函数都认为是缺省构造函数,并且缺省的构造函数只能有一个。
class Date
{
public:
Date()//无参构造函数
{}
Data(int year,int month,int day)//带参构造函数
{
_year=year;
_month=month;
_day=day;
}
Data(int year=2017,int month=03,int day=09)//缺省参数的构造函数
{
_year=year;
_month=month;
_day=day;
}
Data(int year=z017,int month=06))//半缺省参数的构造函数
{
_year=year;
_month=month;
_day=25;
}
private:
int_name;
int_sex;
int _age;
};
void TestDate1()
{
Data d1(); // 调用无参构造函数
Data d2(2017,06,25); // 调用带参构造函数
Data d1();)//调用缺省参数的构造函数
Data d2(2017,03,09))//调用缺省参数的构造函数
}
(2)拷贝构造函数
创建对象时使用同类对象来进行初始化,这时所用的构造函数称为拷贝构造函数(Copy Constructor),拷贝构造函数是特殊的构造函数。
特征:
· 拷贝构造函数其实是一个构造函数的重载。
·拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
· 若未显示定义,系统会默认缺省的拷贝构造函数。缺省的拷贝构造函数会,依次拷贝类成员进行初始化。
下面来实现一个拷贝构造函数
class Data
{
public:
Data()
{}
Data(const Data &d)//拷贝构造函数
{
_year=d._year;
_month=d._month;
_day=d._day;
}
private:
int _year ;
int _month ;
int _day ;
};
void TestDate1 ()
{
Date d1 ;
// 下面两种用法都是调用拷贝构造函数,是等价的。
Date d2 (d1); // 调用拷贝构造函数 在这里函数里面存在一个隐含的this指针把d1的值传给d1,把d2的值传给this
Date d3 = d1; // 调用拷贝构造函数 在这里函数里面存在一个隐含的this指针把d1的值传给d1,把d3的值传给this
}
(3)析构函数
当一个对象的生命周期结束时,C++编译系统会自动调用一个成员函数,这个特殊的成员函数即析构函数(destructor)
构造函数是特殊的成员函数,其特征如下:
·析构函数在类名加上字符~
·析构函数无参数无返回值
·一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。 · 对象生命周期结束时,C++编译系统系统自动调用析构函数。
·注意析构函数体内并不是删除对象,而是做一些清理工作
class Date
{
public :
// 析构函数
~Date()
{}
private :
int _year ;
int _month ;
int _day ;
};
class Array
{
public :
Array (int size)
{
_ptr = (int *)malloc( size*sizeof (int));
}
// 这里的析构函数需要完成清(shi)理(fang)工(kong)作(jian)。
{
if (_ptr )
{
free(_ptr );
_ptr = 0;
}
}
private :
int* _ptr ;
};
运算符的重载
运算符重载特征:
operator+ 合法的运算符 构成函数名(重载<运算符的函数名:operator< ),整个语句没有返回值类型,类型名就代表返回值类型。
重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。
5个C++不能重载的运算符:
. (成员访问运算符)
.* (新成员指针访问运算符)
::(域运算符)
sizeof (sizeof求值运算符)
?:(条件运算符)
(4)赋值运算符重载
拷贝构造函数是创建的对象,使用一个已有对象来初始化这个准备创建的对象。 赋值运算符的重载是对一个已存在的对象进行拷贝赋值。
运算符实际上是一个函数,运算符的重载即是函数的重载。
Date& operator=(const Date& d)
{
if(this != &d) //=左右两个对象不为同一个对象再进行赋值操作
{
this->_day = d._day;
this->_month = d._month;
this->_year = d._year;
}
return *this;
}
重载运算符的运算
对于两个整型变量相加,用户可以调换两个加数的位置,但通过重载运算符实现两个不同类型的对象相加,则不可以。
//前置++
Complex &operator++()
{
_real=real++;
return *this;
}
//后置++
Complex &operator++(int)
{
Complex tmp*this;
real+=1;
return real;
}
//重载赋值运算符
Complex &operator=(int year)
{
_real=real;
}
3.整理隐含的this指针等等,及对运算符重载背后做的事情。
//d1=d2
bool operator==(const date d)
{
return _year==d1.year//_year=>this->_year
&&_month==d1.month
&&_day==d1.day;
}