1 类和对象的基础知识
********************************************
对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型,其定义为:
class 类名{}它们的关系是,对象是类的实例。
类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化。每个对象都是类的一个具体实例,拥有类的成员变量和成员函数。与结构体一样,类只是一种复杂数据类型的声明,不占用内存空间。而对象是类这种数据类型的一个变量,或者说是通过类这种数据类型创建出来的一份实实在在的数据,所以占用内存空间。
********************************************
类的定义
//类是用户自定义的类型,如果程序中要用到类,必须提前说明,或者使用已存在的类(别人写好的类、标准库中的类等),C++语法本身并不提供现成的类的名称、结构和内容。
class student
{
public:
//成员变量
char *_name;
int age;
char sex;
//成员函数
void display()
{
cout<<″age:″<<num<<endl;
cout<<″name:″<<name<<endl;
cout<<″sex:″<<sex<<endl;
}
};
class是 C++ 中新增的关键字,专门用来定义类。Student是类的名称;类名的首字母一般大写,以和其他的标识符区分开。{ }内部是类所包含的成员变量和成员函数,它们统称为类的成员(Member);由{ }包围起来的部分有时也称为类体,和函数体的概念类似。
注意 在类定义的最后有一个分号;,它是类定义的一部分,表示类定义结束了,不能省略。
访问限定符是用于指定成员或者类型的可访问性的关键字。
********************************************
public(公有):public成员在类外可以直接访问
protected(保护) private(私有)
protected和private成员在类外不能被访问。
它们的作用域从该访问限定符出现位置开始直到下一个访问限定符出现时为止。
class的默认访问权限是private.
********************************************
面向对象封装性
面向对象的三个基本特征是:封装、继承、多态。其中,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!
什么是封装?
封装可以隐藏实现细节,使得代码模块化;封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。在面向对象编程上可理解为:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
什么是继承?
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。其继承的过程,就是从一般到特殊的过程。
通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
什么是多态?
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
对象大小的计算
C++中类的成员函数,静态成员是不占类的大小的。类的大小等于基类的大小+子类个non-static成员变量的大小再+非虚基类大小.
1、空类的大小为1字节
2、字节对齐的问题
成员变量需要整齐的存储,所以若是有不同类型的变量(本身占用字节数不同),则所有变量的大小会按照最大的的大小进行补齐,比如说,若是一个类中有个bool型和int型,则bool型也会占用4个字节。若最大的为short,则bool型或者char型会补齐成为2个字节,最大的为double,则都补齐成为8字节。
并且即使成员完全相同但排列不同计算出的类的大小也可能完全不同。
3、虚函数:如果有虚函数,类的大小+4个字节。
4、虚基类指针:如果是虚继承,则子类的大小为:虚基类的大小 + 4个字节(用来存放指向虚基对象的指针)+子类新增成员的大小。
2. 四个默认成员函数及运算符重载相关知识
成员函数隐含this指针参数:成员函数一个隐式的指针形参(构造函数除外);
对象在调用成员函数时,编译器会将对象的地址传递给this指针;
1、构造函数(需用一个公有成员函数对私有的成员变量进行初始化,在对象构造时执行一次,无参的构造函数和带缺省值的构造函数都是缺省构造函数 ,缺省的构造函数只能有一个)
class Date
{
public:
// Date()//无参构造函数
//{
//_year = 2016;
//_month = 7;
// _day = 6;
// }
Date(int year = 1900, int month = 1, int day = 1)//全缺省的构造函数
{
_year = year;
_month = month;
_day = day;
}
}
***************************************************
构造函数特性
1. 函数名与类名相同。
2. 无返回值。
3. 对象构造(对象实例化)时系统自动调用对应的构造函数。
4. 构造函数可以重载。
5. 构造函数可以在类中定义,也可以在类外定义。
6. 如果类定义中没有给出构造函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动 生成缺省的构造函数。
7. 无参的构造函数和全缺省值的构造函数都认为是缺省构造函数,并且缺省的构造函数只能有一个。
***************************************************
2、拷贝构造函数(使用同类对象来初始化;构造函数的重载;若未显示定,系统会调缺省的拷贝构造函数,缺省的拷贝构造函数会依次拷贝类成员进行初始化)
class date
{
public:
date(const int year,consst int month,const int day)
{
_year=year;
_month=month;
_day=day;
}
date(const date& d)
{
_year=d._year;
_month=d._month;
_day=d._day;
}
}
********************************************
特征:
1. 拷贝构造函数是一个构造函数的重载。
2. 拷贝构造函数的参数必须使用引用传参,使用传值方式
会引发无穷递归调用。
3. 如果未显示定义,系统会默认缺省的拷贝构造函数。缺省的拷贝构造函
数会,依次拷贝类成员进行初始化。
********************************************
3、析构函数(当一个对象的生命周期结束时,c++编译器会自动调用析构函数;负责做一些清理工作)
//class SeqList
//{
//public:
// SeqList()
// {
//
// _array = (int*)malloc(sizeof(int)*3);
// _size = 0;
// _capacity = 3;
// }
//
// void PushBack(int x)
// {
// //CheckCapacity();
// _array[_size] = x;
// _size++;
// }
//
// ~SeqList()
// {
// // 清理工作
// free(_array);
// _size = _capacity = 0;
// }
********************************************
特征:
1. 析构函数在类名加上字符~。
2. 析构函数无参数无返回值。
3. 一个类有且只有一个析构函数。若未显示定义,
4. 系统会自动生成缺省的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
5. 注意析构函数体内并不是删除对象,而是做一些清理工作.
********************************************
4、赋值运算符的重载
它是两个已有对象一个给另一个赋值的过程。它不同于拷贝构造函数,拷贝构造函数是用已有对象给新生成的对象赋初值的过程。
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void operator=(const Distance &D )
{
feet = D.feet;
inches = D.inches;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main()
{
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// 使用赋值运算符
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
结果:
First Distance : F: 11 I:10
Second Distance :F: 5 I:11
First Distance :F: 5 I:11
5.运算符重载相关知识
[详解] (http://blog.youkuaiyun.com/dingyuanpu/article/details/5852825)
3.隐含的this指针
当我们在进入一所房子后,可以看见房子里的桌子,椅子,地板等。但看不到房子的全貌。对于一个类的实例来说,你可以看到它的成员函数,成员不变量但实力的本身呢 ?this是一个指针,它时时刻刻指向这个实例。
********************************************
1.this指针的类型: 类类型 * const
2.this指针并不是类本身的一部分,不影响sizeof(类)的大小
3.this的作用域在类成员的内部
4.this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递。
我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时
显示传递对象的地址给this指针。
********************************************
void Display()//(Date* this)
{
cout<<_year<<endl;
//cout<<this->_year<<endl;
}