类(Class)

类(class)是对于结构体(struct)的增强,即在struct的基础上增加了一些特性,来满足一些新的需求。

访问修饰符

1.public	//可以在外部被访问
2.private	//只能在类的内部被访问,不能被外部访问
3.protect	//该成员不能被外部访问,同private;可以被子类继承,同public

访问成员变量的方式

class object
{
public:
	int a;
	double b;
}

void main()
{
	//访问方式1
	object obj;
	obj.a = 10;
	//访问方式2
	object *p = &obj;	//指针类型
	p->a = 10;
	renturn;
}

内存视图
class类型的内存视图,原理上和struct一样:各成员依次排列在内存中。
类的大小由成员变量相关,和成员函数的数量无关,成员函数不占空间,如果函数被声明为virtual,则大小会发生变化,一般是4个字节,由编译器决定,不同的编译器可能不同。

this指针
1.不受到访问修饰符(public/private)的限制
2.可以访问成员变量以及成员函数
3.this->可以省略,编译器会自动会帮你加上

重名问题
就近原则,如果要访问全局变量/函数而非成员变量/函数,则需要加上::,例如::x,如果要访问成员变量/函数,则需要加上this->

命名规范
1.类名——每个单词的首字母大写,一般用名词形式,例如GoodObject;
2.成员函数——每个单词的首字母大写,一般用动词形式,例如SendMessage;
3.成员变量——m_开头,小写开头,第二个单词开头大写,例如m_maxSize;

头文件与源文件
函数如果写在类体里面,编译器按照inline函数的规则编译;若写在类体之外,则是普通函数。

构造函数
1.函数名必须与类名相同,普通函数不能与类名相同
2.没有返回值
3.构造函数可以带参数,可以重载
4.构造函数不显式调用,只是在创建对象时被编译器自动调用
5.构建函数作用——初始化对象

6.必须要有默认的构造函数,不然该类就不能构造数组
7.如果类没有任何构造函数,则编译器会自己家一个默认的构造函数

拷贝构造函数
1.是构造函数的一种,所以函数名是类名,没有返回值
2.是特殊的构造函数:参数形式是固定的
3.并不显示调用,而是由编译器隐式调用
4.当没有拷贝构造函数时,编译器会默认提供一个拷贝构造函数,默认将每一个成员逐个拷贝
5.拷贝构造函数必须为引用拷贝构造函数必须为引用

class Object
{
public:
	Object(const Object& other) //拷贝构造函数必须为引用
	{
		//拷贝构造函数
	}
	Object()
	{
		//普通构造函数
	}
	
	//赋值运算函数代码详见《剑指offer》25页面试题1
	//赋值函数,即赋值运算符重载
	//赋值函数指的是两个对象a和b都已经被构造,所以只需要将a复制给b
	//而拷贝构造函数指的是,b还没有被事先构造
	Object& b = (const Object &a)//赋值函数(赋值运算符重载)
	{	
		//将a中的成员变量复制到b
		return *this;
	}
}

void Test(Object obj)
{
	//...
}

//拷贝构造函数的三种调用方式
Object a;
Object b(a);	//等价于Object b = a;
Object *p = new Object(a);
Test(a);
//attention
Object b(a);	//等价于Object b = a, 拷贝,会调用拷贝构造函数
Object b;
b = a;	//赋值,不调用拷贝构造函数

析构函数
1.名称固定,类名前加上~
2.没有返回值
3.不能带任何参数,不能重载
4.不显式调用,对象被销毁的时候,编译器自动调用
5.析构函数作用——对象销毁之前,清理善后工作,释放资源,比如释放内存,关闭打开了的文件

6.如果类没有析构函数,则编译器会自己家一个默认的析构函数

成员的初始化与析构
若成员变量也是class时,对象被构造时,成员变量也被构造;对象被析构时,成员变量也被析构。
1.成员变量构造->对象构造->对象析构->成员变量析构
2.如果成员变量有多个是class的对象,则写在前面的那个成员变量先构造,后析构
3.初始化列表,在构造函数后面指定类的成员的初始化构造参数

class Object
{
public:
	Object():m_child(1, 2)
	{
	}
	~Object()
	{
	}
	child m_child;
}
class Child 
{
public:
	Child (int x, int y)
	{
	}
	~Child ()
	{
	}
	int x, y;
}

类的继承

//B(子类,派生类)继承于A(父类,基类)
//子类自动继承父类中所有的public成员
//子类继承父类时,内存中,父类的成员在前面,子类成员在后面,对于父类的私有成员,也会出现在子类的内存空间中,只是编译器限制了子类的访问
class B : public A
{
}
//创建子类对象,则调用父类构造函数->子类构建函数->子类析构函数->父类析构函数

//若父类存在多个构造函数,则默认调用默认构造函数,若需要调用指定构造函数
class B : public A
{
public:
	B():A(1,1)
	{
		//...
	}
}
函数重写相关
//函数重写,子类可以重写父类的函数
class A
{
	void Test()
	{
		cout<<"A";
	}
}
class B : public A
{
	void Test()
	{
		cout<<"B";
	}
}

//如果只是想在父类函数的基础上添加代码,则可以
class A
{
	void Test()
	{
		cout<<"A";
	}
}
class B : public A
{
	void Test()
	{
		A::Test();
		cout<<"B";
	}
}

//用父类指针指向子类对象,从语法上来讲是直接允许的
Tree* p = new AppleTree;	//苹果树也是树
//此时,若存在函数重写(不是virtual),则调用的是父类的函数,若函数为virtual,则调用的是子类的函数
//即加上了virtual后,会根据对象的实际类型,决定调用那个函数

//关键字virtual
1.当一个成员函数需要子类重写,那么在父类中应该将其声明为virtual,有时将声明为virtual的函数称为虚函数
2.若父类中的函数为virtual,则子类中的函数默认为virtual,关键字virtual可以加,也可以不加
3.当一个类被继承时,父类的析构函数应该被声明为virtual,否则会存在潜在的问题
Parent* p = new Child();
delete p;	//调用的是父类的析构函数,则部分资源没有被释放 
4.构造函数不能加virtual,否则编译器会直接报错
//多重继承
//如果AB中存在相同的变量或者成员函数,编译器会报错
class C : public A, public B
{
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值