Week-10-类与对象


前言

本篇文章主要介绍了C++类和对象


1. 类和对象的定义

1.1 类定义的格式:

class 类名{
public:
//<共有数据和函数>
protected:
//<保护数据和函数>
private:
//<私有数据和函数>
};
/*Person类的定义*/
#include<iostream>

using namespace std;

class Person {
public:
	/*函数既可以在类内定义,也可以先在类内声明,在类的外部l定义,
	在类外定义时要指定命名空间为Person(类名)*/
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
	};
	void setName(string name);
	void setAge(int age);
private:
	string name;
	int age;
};
void Person::setName(string name) {
	this->name = name;//this是一个特殊的指针,指向这个对象本身
}
void Person::setAge(int age) {
	this->age = age;
}

1.2 类的构造函数

(1)作用:在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。
(2)特点:
  1)自动调用(在创建新对象时,自动调用)
  2)构造函数的函数名,和类名相同
  3)构造函数没有返回类型
  4)可以有多个构造函数(即函数重载形式)
(3)构造函数的种类:
  默认构造函数
  自定义的构造函数
  拷贝构造函数
  赋值构造函数

1.2.1 默认构造函数

没有参数的构造函数,称为默认构造函数。
(1)合成的默认构造函数:
  1)如果数据成员使用了“类内初始值”,就使用这个值来初始化数据成员(C++11)
  2)否则,就使用默认初始化(实际上,不做任何初始化)

class Person {
public:
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
	};
private:
	string name = "未命名";//c11之后才支持这样初始化
	int age = 0;
};

(2)自定义的默认构造函数

class Person {
public:
	Person();//默认构造函数的声明
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
	};
private:
	string name = "未命名";
	int age = 0;
};
Person::Person() {
	cout << "调用了自定义的默认构造函数" << endl;
}

1.2.2 自定义的构造函数

class Person {
public:
	Person();
	Person(string name, int age);
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
	};	
private:
	string name = "未命名";
	int age = 0;
};
Person::Person() {
	cout << "调用了自定义的默认构造函数" << endl;
}
Person::Person(string name, int age) {
	this->name = name;
	this->age = age;
	cout << "调用了自定义的构造函数" << endl;
}

1.2.3 拷贝构造函数

(1)自定义的拷贝构造函数(参数必须是其他该类对象的引用)

class Person {
public:
	Person();
	Person(string name, int age);
	Person(const Person &person);
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
	};
private:
	string name = "未命名";
	int age = 0;
};

Person::Person() {
	cout << "调用了自定义的默认构造函数" << endl;
}
Person::Person(string name, int age) {
	this->name = name;
	this->age = age;
	cout << "调用了自定义的构造函数" << endl;
}
Person::Person(const Person &person) {
	cout << "调用自定义的拷贝构造函数" << endl;
	name = person.name;
	age = person.age;
}

(2)默认的拷贝构造函数
不定义拷贝构造函数,编译器会生成“合成(默认)的拷贝构造函数”,但合成的拷贝构造函数使用的是浅拷贝,而自定义的拷贝构造函数我们可以定义为深拷贝

#include<iostream>

using namespace std;

class Person {
public:
	Person();
	Person(string name, int age, const char *addr);
	Person(const Person &person);
	void printBasicInfo() {
		cout << this->name << endl;
		cout << this->age << endl;
		cout << this->addr << endl;
		printf("%p\n", &this->addr[0]);
	};
	void setAddr(const char *newAddr) {
		if (!newAddr) {
			return;
		}
		strcpy_s(addr, 64, newAddr);
	}

private:
	string name = "未命名";
	int age = 0;

	char *addr = NULL;
};

Person::Person() {
	cout << "调用了自定义的默认构造函数" << endl;
	name = "未命名";
	age = 0;
}
Person::Person(string name, int age,const char *addr) {
	cout << "调用了自定义的构造函数" << endl;
	this->name = name;
	this->age = age;
	this->addr = new char[64];
	strcpy_s(this->addr, 64, addr);

}

Person::Person(const Person &person) {
	cout << "调用自定义的拷贝构造函数" << endl;
	name = person.name;
	age = person.age;

	//(1)浅拷贝:这里只是单纯的将person.addr的存储的地址给addr,所以addr与person.addr指向了同一内存空间
	//	   所以当addr或者person.addr的值改变时,他们会同时改变
	addr = person.addr;

	//(2)深拷贝:这里我们给addr重新分配内存空间,
	//然后把person.addr所指向内存空间的值拷贝给addr所指向的内存空间
	/*addr = new char[64]; 
	strcpy_s(addr, 64, person.addr);*/
}

int main(void) {

	Person peo2("Tree", 20,"China");
	Person peo3 = peo2;
	Person peo4(peo2);
	
	peo2.setAddr("USA");
	cout << endl << "peo2:" << endl;
	peo2.printBasicInfo();
	cout << endl << "peo3:" << endl;
	peo3.printBasicInfo();
	cout << endl << "peo4:" << endl;
	peo4.printBasicInfo();
	
	system("pause");
	return 0;
}

浅拷贝效果:
浅拷贝
深拷贝效果:
在这里插入图片描述
(3)调用拷贝构造函数的几种情况:
1. 调用函数时,实参是对象,形参不是引用类型, 如果函数的形参是引用类型,就不会调用拷贝构造函数(或者用指针)

void printPersonInfo(Person peo) {//调用一次
	peo.printBasicInfo();
}

2. 函数的返回类型是类,而且不是引用类型

Person alterPersonAddr(Person &peo) {
	peo.setAddr("Japan");
	peo.printBasicInfo();
	return peo; //调用一次
}

3. 对象数组的初始化列表中,使用对象。

	Person peo1("Tree", 20, "China");
	Person peo2("Rock", 1024, "China");
	Person peo3("Martin", 88, "China");

	Person peos[] = { peo1,peo2,peo3 };//调用三次

1.2.4 赋值构造函数

默认赋值构造函数也是进行浅拷贝,在自定义的赋值构造函数中可以实现深拷贝

	//赋值构造函数的声明,实际上是进行运算符重载
	Person& operator=(const Person &people);
//实现
Person& Person::operator=(const Person &people) {
	if(this == &people){
		return *this;//检测是不是给自己赋值P1 = P1
	}
	cout << "调用了自定义的赋值构造函数" << endl;
	this->name = people.name;
	this->age = people.age;

	strcpy_s(addr, 64, people.addr);

	return *this;//方便连续的赋值 P1 = P2 = P3;
}

1.3 类的析构函数

作用:
  对象销毁前,做清理工作。具体的清理工作,一般和构造函数对应比如:如果在构造函数中,使用new分配了内存,就需在析构函数中用delete释放。如果构造函数中没有申请资源(主要是内存资源),那么很少使用析构函数。
函数名:
  ~类型    没有返回值,没有参数,最多只能有一个析构函数
访问权限:
  一般都使用public
使用方法:
  不能主动调用。
  对象销毁时,自动调用。
  如果不定义,编译器会自动生成一个析构函数(什么也不做)

Person::~Person() {
	cout << "调用了析构函数" << endl;
	delete addr;
}

2.对象的基本使用

2.1 对象的定义

(1)类名 对象名
(2)类名 对象名(参数列表)

Person peo1;
Person peo2();//构造方法定义并初始化

2.2 对象调用方法

Person peo;
peo.printBasicInfo();
//通过指针调用
Person *p_peo;
p_peo->printBasicInfo();


3.类中的静态和const

3.1 类的静态数据成员

class Person{
private:
	//类的静态数据成员,没有const修饰的静态变量,在定义时是不能初始化的
	static int createCount;
}
/*
对于非const的类静态成员,只能在类的实现文件(类的定义放在头文件中,函数的实现放在.cpp文件中)中初始化。
const类静态成员,可以在类内设置初始值,也可以在类的实现文件中设置初始值。(但是不要同时在这两个地方初始化,初始化两次的话,以类外为准)
*/
int Person::createCount = 0;

3.2 类的静态成员函数

1. 可以直接通过类来访问【更常用】,也可以通过对象(实例)来访问。
2. 在类的静态方法中,不能访问普通数据成员和普通成员函数(对象的数据成员和成员函数)
3. 在类的静态成员函数中是不能使用this指针的。

class Person{
public:
	static int getCount();
private:
	static int Count;
}


int Person::createCount = 0;
//不要加static
int Person::getCount(){
	// 静态方法中,不能访问实例成员(普通的数据成员)
	// cout << age;

	// 静态方法中,不能访问this指针
	// 因为this指针是属于实例对象的
	// cout << this;

	//静态方法中,只能访问静态数据成员;
	//但实例成员可以访问静态成员
	return createCount ;
}

//调用:
cout << Person::getCount();

3.3 类中的 const 数据成员

const数据成员的初始化方式:
(1) 使用类内值(C++11支持)
(2) 使用构造函数的初始化列表
(如果同时使用这两种方式,以初始化列表中的值为最终初始化结果)
注意: 不能在构造函数或其他成员函数内,对const成员赋值!

class Person{
public:
	Person();
	Person(string name, int age, const char *addr,string bldType);
	//...
private:
	const string bloodType = "未知"; //类内值
}
Person::Person():bloodType("未知") { //1.初始化列表初始bloodType
	cout << "调用了自定义的默认构造函数" << endl;
	name = "未命名";
	age = 0;
	addr = new char[64];
	strcpy_s(addr, 64, "China");
	
	createCount++;
}
Person::Person(string name, int age, const char *addr ,string bldType):bloodType(bldType) { //2.初始化列表初始bloodType
	cout << "调用了自定义的构造函数" << endl;
	this->name = name;
	this->age = age;
	this->addr = new char[64];
	strcpy_s(this->addr, 64, addr);
	createCount++;
}

//

3.4 const 成员函数

(1)const成员函数不能修改类内变量的值
(2)const类型的对象只能调用const成员函数(构造函数、析构函数除外)

class Person{
public:
	void printBasicInfo() const{
		cout << this->name << endl;
		cout << this->age << endl;
		cout << this->addr << endl;
		cout << this->bloodType << endl;
	};
private:
	//...
}

const Person peo1;
peo1.printBasicInfo();


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值