1.什么是面向对象?
面向对象是一种程序设计范型,同时也是一种程序开发的方法
对象指的是类的实例,将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性,灵活性和扩展性
面向对象的三大特性:
封装、继承和多态
2.类的大小?为什么要内存对齐?内存对齐的计算?空类的计算
类的大小是根据类中成员类型来判定,并且有内存对齐问题
#include <iostream>
#include <windows.h>
using namespace std;
class Person
{
public:
};
int main()
{
cout << sizeof(Person) << endl;
}
空类大小为1,因为定义的Person需要用一个字节来占位,让别人知道Person这个类的存在
#include <iostream>
#include <windows.h>
using namespace std;
class A
{
public:
char a;
double b;
};
int main()
{
cout << sizeof(A) << endl;
}
结果为16
因为存在内存对齐问题,而VS中默认对齐数位8,char类型占一个字节,剩下的8-1=7个字节不够double(8个字节)类型存放,所以就把b这个成员变量放在下一个8个字节中,也就是说着16个字节中,第一个字节存放a成员变量,从2-8这7个字节为空,没有变量存放,9-16这8个字节存放b成员变量。所以结果为16
#include <iostream>
#include <windows.h>
using namespace std;
class A
{
public:
char a;
double b;
};
class B
{
public:
char* a1;
A b;
char b1;
};
int main()
{
cout << sizeof(B) << endl;
}
结果为32
上面的例子已经说了A这个类的大小为16,那么B这个类的大小是这样计算:
a1的类型为char类型的指针,指针在32位操作系统下为4个字节,所以按8字节对齐,剩余的4个字节存不下b成员变量,因为b成员变量的类型是A,b大小为16个字节,所以将这4个字节放弃,在9-24这16个字节存放b成员变量,b1是char类型,占一个字节,但是因为后面没有成员变量了,所以b1仅仅只将25这个字节占领,26-32这7个字节没有用到,但是也是在类大小中的
所以B这个类的大小为8(char* a1) + 16(A b) + 8(char b1) = 32个字节
为什么要内存对齐?
<1>平台原因(移植原因)
不是所有的硬件平台都能访问任意地址上的任意数据的;
某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
<2>性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问
3.类的4个默认成员函数的详细使用及细节
<1>构造函数
1、无参构造函数
2、带参构造函数
#include <iostream>
#include <windows.h>
using namespace std;
class Date
{
public:
//1、无参构造函数 系统默认给每个类创建的构造函数
Date()
{}
//2、带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1; //调用无参构造函数
Date d2(2010,1,1); //调用带参构造函数
system("pause");
return 0;
}
3、缺省参数构造函数
//3、缺省参数构造函数
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int main()
{
Date d1; //调用缺省构造函数
return 0;
}
4、半缺省参数构造函数
//4、半缺省参数构造函数
Date(int year, int month = 1)
{
_year = year;
_month = month;
_day = 1;
}
int main()
{
Date d2(2010);
return 0;
}
<2>拷贝构造函数
创建新对象时使用同类已有对象进行初始化操作
拷贝构造是构造函数的重载
拷贝构造函数的参数必须使用引用传参,如直接传值会引发无穷递归调用
//构造
Date()
{}
//拷贝构造
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
int main()
{
Date d1; //调用构造
Date d2(d1); //调用拷贝构造
return 0;
}
<3>析构函数
析构函数在类名前加字符~
一个类只有一个析构函数,如自己没定义,则系统会自动生成一个析构函数
当对象生命周期结束,系统会自动调用析构函数进行清理,并不删除对象
//析构函数
~Date()
{}
<4>赋值运算符重载
赋值运算符重载是对一个已存在的对象进行赋值
Date& operator=(const Date& d)
{
if(this != &d){
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}
return *this;
}
int main()
{
Date d1;
Date d2(2018, 1, 1);
d1 = d2;
return 0;
}