C++基础知识/类/类大小/类的默认成员函数

类和对象
类的定义
这里写图片描述
看图总结:类中包含成员函数与成员变量两部分。可加上访问限定符对成员变量和成员函数进行访问权限的限制。

#include<iostream>
using namespace std;

class Person
{
public://这里定义为公有的,是为了在类的外面直接访问,如果这里不写public,则编译器默认为私有的
    void Display()
    {
        cout << _name << "-" << _sex << "-" << _age << endl;
    }
    char* _name;//名字
    char* _sex;//性别
    int _age;//年龄
};

void Test()
{
    Person one;//这里定义了一个类的对象,并进行了赋值
    one._name = "zhang";
    one._sex = "男";
    one._age = 20;
    one.Display();

    Person* two=&one;
    two->_name = "li";
    two->_sex = "男";
    two->_age = 20;
    two->Display();
}
int main()
{
    Test();
    system("pause");
    return 0;
}
三种访问限定符:

public:公有,可在类的外面直接进行访问。
protected:保护、private:私有,这两个都只能在类的里面进行访问,在类的外面不能直接进行访问。
注:都是从当前访问限定符开始直至下一个访问限定符的出现,或者直接到当前作用域结尾的大括号为止。如果没有标明访问限定符,则编译器默认为私有的。
作用域:
全局域、局部域、类域、名字空间域
类的作用域:
每个类都定义了自己的作用域,类的成员(成员函数/成员变量)都在这个类的作用域内,成员函数内可任意访问成员变量和其它成员函数。
对象可以通过直接访问公有成员,指对象的指针通过->也可以直接访问对象的公有成员。
在类体外定义成员,需要使用::作用域解析符指明成员属于哪个类。
类实例化对象:
1.类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。
2.一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间存储类成员变量。
3.做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑
存在,同样的类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
这里写图片描述
成员函数的声明和定义:

1.类内定义成员函数
class Person
{
public :
void Display ()
{
cout<<_name <<"-"<< _sex<<"-" <<_age<< endl;
}
public :
char* _name; // 名字
char* _sex; // 性别
int _age; // 年龄
};
2.类外定义成员函数
class Person
{
public :
void Display ();
public :
char* _name; // 名字
char* _sex; // 性别
int _age; // 年龄
};
void Person::Display ()
{
cout<<_name <<"-"<< _sex<<"-" <<_age<< endl;
}
类大小的计算:

同结构体大小计算:1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
//对齐数=编译器默认的一个对齐数与该成员大小的较小值。
VS中默认的值为8
gcc中的默认值为4
3.结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数
注:成员函数不占大小;如果未实例化,则大小为1,表示占位。
这里写图片描述
隐含的this指针
1. 每个成员函数都有一个指针形参,它的名字是固定的,称为this指针,this指针是隐式的。(构造函数比较特殊,没有这个隐含this形参)
2. 编译器会对成员函数进行处理,在对象调用成员函数时,对象地址作实参传递给成员函数的第一个形参this指针。
3. this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时显示传递对象的地址给this指针。
这里写图片描述

类的六个默认成员函数:

构造函数、拷贝构造函数、析构函数、赋值操作符重载、取地址操作符重载、const修饰的取地址操作符重载
构造函数:
成员变量为私有的,要对它们进行初始化,必须用一个公有成员函数来进行。同时这个函数应该有且仅在定义对象时自动执行一次,这时称调用的函数称为构造函数(constructor)。
构造函数是特殊的成员函数,其特征如下:
1. 函数名与类名相同。
2. 无返回值。
3. 对象构造(对象实例化)时系统自动调用对应的构造函数。
4. 构造函数可以重载。
5. 构造函数可以在类中定义,也可以在类外定义。
6. 如果类定义中没有给出构造函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动
生成缺省的构造函数。
7. 无参的构造函数和全缺省值的构造函数都认为是缺省构造函数,并且缺省的构造函数只能有一个。

无参构造函数&带参构造函数

class Date
{
public :
// 1.无参构造函数
Date ()
{
_year = year ;
_month = month ;
_day = day ;
}
// 2.带参构造函数
Date (int year, int month , int day )
{
_year = year ;
_month = month ;
_day = day ;
}
private :
int _year ;
int _month ;
int _day ;
};
void TestDate1 ()
{
Date d1 ; // 调用无参构造函数
Date d2 (2015, 1, 1); // 调用带参的构造函数
Date d3 (); // 注意这里没有调用d3的构造函数定义出 d3
}

带缺省参数的构造函数

class Date
{
public :
// 3.缺省参数的构造函数
Date (int year = 2000, int month = 1, int day = 1)
{
_year = year ;
_month = month ;
_day = day ;
}
// 4.半缺省参数的构造函数(不常用)
Date (int year, int month = 1)
{
_year = year ;
_month = month ;
_day = 1;
}
private :
int _year ;
int _month ;
int _day ;
};
void Test()
{
Date d1 ; // 调用缺省构造函数
Date d2 (2015, 1, 9); // 调用缺省构造函数
}
备注:若缺省参数声明和定义分离,则可以在声明或定义中给默认参数。
拷贝构造函数

创建对象时使用同类对象来进行初始化,这时所用的构造函数称为拷贝构造函数(Copy Constructor),拷贝构造函数是特殊的构造函
数。
特征:
1. 拷贝构造函数其实是一个构造函数的重载。
2. 拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
3. 若未显示定义,系统会默认缺省的拷贝构造函数。缺省的拷贝构造函数会,依次拷贝类成员进行初始化。

class Date
{
public :
Date()
{}
// 拷贝构造函数
Date (const Date& d)
{
_year = d ._year;
_month = d ._month;
_day = d ._day;
}
private :
int _year ;
int _month ;
int _day ;
};
void TestDate1 ()
{
Date d1 ;
// 下面两种用法都是调用拷贝构造函数,是等价的。
Date d2 (d1); // 调用拷贝构造函数
Date d3 = d1; // 调用拷贝构造函数
}

这里写图片描述
解析构造函数
当一个对象的生命周期结束时,C++编译系统会自动调用一个成员函数,这个特殊的成员函数即析构函数(destructor)
构造函数是特殊的成员函数,其特征如下:
1. 析构函数在类名加上字符~。
2. 析构函数无参数无返回值。
3. 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
5. 注意析构函数体内并不是删除对象,而是做一些清理工作。(怎么理解这里的清理工作?参看下面的EXP0)

class Date
{
public :
// 析构函数
~Date()
{}
private :
int _year ;
int _month ;
int _day ;
};
EXP0
class Array
{
public :
Array (int size)
{
_ptr = (int *)malloc( size*sizeof (int));
}
// 这里的析构函数需要完成清(shi)理(fang)工(kong)作(jian)。
~ Array ()
{
if (_ptr )
{
free(_ptr );
_ptr = 0;
}
}
private :
int* _ptr ;
};
运算符重载

为了增强程序的可读性,C++支持运算符重载。
运算符重载特征:
1. operator+合法的运算符构成函数名(重载<运算符的函数名:operator<)。
2. 重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。
3. 5个C++不能重载的运算符: .*/::/sizeof/?:/.
赋值运算符重载
拷贝构造函数是创建的对象,使用一个已有对象来初始化这个准备创建的对象。
赋值运算符的重载是对一个已存在的对象进行拷贝赋值。

class Date
{
public :
Date()
{}
// 拷贝构造函数
Date (const Date& d)
: _year(d._year)
, _month(d._month)
, _day(d._day)
{}
// 赋值操作符的重载
// 1.思考为什么operator=赋值函数需要一个 Date&的返回值,使用void做返回值可以吗?请验证
Date& operator = (const Date& d)
{
// 2.这里的if条件判断是在检查什么?
if (this != &d)
{
this->_year = d. _year;
this->_month = d. _month;
this->_day = d. _day;
}
return *this ;
}
private:
int _year ;
int _month ;
int _day ;
};
void Test ()
{
Date d1 ;
Date d2 = d1; // 调用拷贝构造函数
Date d3 ;
d3 = d1 ; // 调用赋值运算符的重载
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值