C++学习笔记——类和对象-创新互联

文章目录
  • 前言
  • 一、类与对象的概念
  • 二、封装
    • 1. 封装的作用
    • 2. 代码示例
  • 三、类的初始化和清理
    • 1. 构造函数&析构函数
    • 2. 拷贝构造函数
    • 3. 深拷贝&浅拷贝
    • 4.初始化列表
    • 5.类对象作为类成员
    • 6.静态成员
  • 四、类成员储存方式
  • 五、this指针
  • 六、const修饰成员函数

目前创新互联建站已为近千家的企业提供了网站建设、域名、网页空间、网站托管、服务器托管、企业网站设计、滨湖网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
前言

类和对象的学习主要包括一下几点:

  • 类与对象的概念
  • 封装
  • 类的初始化和清理
  • 类的储存
  • this指针
  • 友元
  • 运算符重载
  • 继承
  • 多态
    接下来我将对以上内容进行一一讲解。

一、类与对象的概念

类:用来对实体(对象)进行描述,对象的属性,以及对象的行为。

对象:对象可以是一个实体、一个名词、一个可以想象为有自己标识的任何东西,所有东西都能当做对象,Everything is object(万物皆对象)。

C++面向对象的三大特性为:封装、继承、多态。

二、封装 1. 封装的作用
  • 将属性和行为作为一个整体,然后通过对象来完成操作。
  • 使属性和行为附加权限
  • 尽量使代码或者功能独立
2. 代码示例

求圆的周长

#includeusing namespace std;
#define PI = 3.14; //宏定义π的值

//封装一个圆类,求圆的周长
//class代表设计一个类,后面跟着的是类名
class Circle
{public: //访问权限为公共的
	//行为:
	//获取到圆的周长
	double calculateZC()
	{return 2 * PI * m_r;//返回计算的圆的周长
	}
	void func()
	{m_r = 10;
	}
private:
	//属性:
	int m_r;//半径
};
int main() 
{Circle c1;//创建一个圆的对象
	//c1.m_r = 10; //m_r为私有属性,无法进行赋值操作
	c1.func();//调用幅值的函数
	cout<< "圆的周长为: "<< c1.calculateZC()<< endl;//打印
	system("pause");
	return 0;
}
三、类的初始化和清理 1. 构造函数&析构函数

构造函数:

  • 用于创建对象时为对象的成员属性赋值
  • 没有返回值也不写void
  • 函数名和类名相同
  • 格式:类名() { }
  • 可以重载
  • 当实例对象的时候,无需手动调用,会自动调用,只调用一次
  • 编译器会提供默认的构造函数
  • 定义了其他的构造函数,编译器不会提供默认构造函数
  • 分类:无参构造函数,有参构造函数,拷贝构造函数

构造函数的调用方式:

  1. 括号法
  2. 显示法
  3. 隐式转换法

析构函数:

  • 用于对象销毁前系统自动调用,执行一些清理工作
  • 没有返回值也不写void
  • 格式:~类名() { }
  • 可以重载
  • 对象销毁时会自动调用,无需手动调用,只调用一次

代码示例:

#includeusing namespace std;

class Person
{public:
	//无参构造函数
	Person()
	{cout<< "Person的构造函数调用"<< endl;
	}
	//有参构造函数
	Person(int a)
	{m_A = a;
		cout<< "Person的有参构造函数!"<< endl;
	}
	//拷贝构造函数
	Person(const Person &p)
	{m_A = p.m_A;
		cout<< "Person的拷贝构造函数!"<< endl;
	}
	//析构函数
	~Person()
	{cout<< "Person的析构函数调用"<< endl;
	}
private:
	int m_A;
};

int main()
{Person p1;//无参构造函数的调用,调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
	//有参构造函数的调用
	Person p2(10);//括号法调用有参构造函数
	Person p3 = Person(10);//显式法调用有参构造函数
	Person p4 = Person(p3);//显式法调用拷贝构造函数
	Person p5 = 10;//隐式转换法调用有参构造函数
	Person p6 = p5;//隐式转换法调用拷贝构造函数
	system("pause");
	return 0;
}
2. 拷贝构造函数

拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。

在c++中拷贝构造函数通常在以下三种情况下调用

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

使用时需要注意:

  • 如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
  • 如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造
  • 如果用户提供拷贝构造,编译器不会提供其他构造函数

示例代码:

class Person 
{public:
	Person() 
	{cout<< "无参构造函数!"<< endl;
		mAge = 0;
	}
	Person(int age) 
	{cout<< "有参构造函数!"<< endl;
		mAge = age;
	}
	Person(const Person& p) 
	{cout<< "拷贝构造函数!"<< endl;
		mAge = p.mAge;
	}
	~Person() 
	{cout<< "析构函数!"<< endl;
	}
private:
	int mAge;
};
//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test01() 
{Person p1(100); //创建man对象
	Person p2(p1)); //调用拷贝构造函数,做对象拷贝操作
	
}
//2. 值传递的方式给函数参数传值,相当于Person p1 = p;
//对象作为参数,实质是调用了拷贝构造函数
void doWork(Person p1) {}
void test02() 
{Person p; //无参构造函数
	doWork(p);
}
//3. 以值方式返回局部对象,实质是调用了拷贝构造函数
Person doWork2()
{Person p1;
	cout<< (int *)&p1<< endl;
	return p1;
}
void test03()
{Person p = doWork2();
	cout<< (int *)&p<< endl;
}
3. 深拷贝&浅拷贝

浅拷贝:简单的赋值拷贝操作,不重新申请资源
深拷贝:在堆区重新申请空间,进行拷贝操作

示例代码:

#includeusing namespace std;

class Person
{public:
	Person()
	{cout<< "无参构造函数调用"<< endl;
	}
	~Person()
	{if (m_Height != NULL)
		{	delete m_Height;
			m_Height = NULL;
		}
		cout<< "析构函数的调用"<< endl;
	}
	Person(int age, int height)
	{m_Age = age;
		m_Height = new int (height);
		cout<< "有参构造函数的调用"<< endl;
	}
	Person(const Person& p)
	{m_Age = p.m_Age;
		//m_Height = p.m_Height;
		m_Height = new int(*p.m_Height);
		cout<< "拷贝构造函数的调用"<< endl;
	}

	int m_Age;
	int* m_Height;
};
void test02()
{Person p1(10,100);

	Person p2(p1);
}
//如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
int main()
{test02();
	system("pause");
	return 0;
}

Person类中的m_Height成员是一个指针变量,如果将Person类中的拷贝构造函数关于m_Height 的复制操作写为:m_Height = p.m_Height; 此时该拷贝构造函数为系统默认的拷贝构造函数的形式。
代码编译没有错误,但是运行后会报错:
在这里插入图片描述
此报错的原因为:
系统提供的默认构造函数为浅拷贝操作,并没有为变量开辟新的内存空间,所以p1和p2两个对象的m_Height成员都指向了同一块地址,导致析构函数对同一块地址释放了两次。
所以必须将拷贝构造函数中的m_Height幅值操作写为m_Height = new int(*p.m_Height); 则可以开辟新的内存,避免了内存的重复释放。

4.初始化列表

C++提供了初始化列表语法,用来初始化属性。
语法:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式。
构造函数():属性1(值1),属性2(值2)… {}

示例代码:

#includeusing namespace std;
class Person
{public:
	Person(int a, int b) :m_R(a), age(b) {}
	void aprint()
	{cout<< m_R<< age<< endl;
	}
private :
	int m_R;
	int age;
};
int main()
{Person p(10,100);

	p.aprint();

	system("pause");
	return 0;
}
5.类对象作为类成员

在C++中,类对象也可以作为一个类成员。

示例代码:

#includeusing namespace std;
class Phone
{public:
	Phone(string phone) :m_PhoneName(phone)
	{cout<< "Phone 的构造"<< endl;
	}
	~Phone()
	{cout<< "Phone 的析构函数"<< endl;
	}
	string m_PhoneName;
};
class Person
{public:
	Person(string name, string phone) :m_Name(name), m_Phone(phone)
	{cout<< "Person 的构造"<< endl;
	}
	~Person()
	{cout<< "Person 的析构函数"<< endl;
	}
	void playGame()
	{cout<< m_Name<< " 使用"<< m_Phone.m_PhoneName<< " 牌手机!"<< endl;

	}
	string m_Name;
	Phone m_Phone;
};
void test01()
{Person p = Person("张三", "iphone xR");
	p.playGame();
}
int main()
{test01();
	system("pause");
	return 0;
}
6.静态成员

由关键字static修饰的成员变量和成员函数,成为静态成员。
静态成员所有对象共享同一块内存,不管有多少对象,静态成员只有一份存于公共内存中。
静态成员变量在类内声明,类外初始化。

示例代码:

#includeusing namespace std;
class Person
{public:
	static int m_B;
private:
	static int m_A;
};
int Person::m_A = 100;//私有成员也需要在类外初始化
int Person::m_B = 200;
int main()
{Person p1;
	Person p2;
	//因为占用同一块内存,所以两个对象打印的m_B的值相等。
	cout<< p1.m_B<< endl;
	cout<< p2.m_B<< endl;
	system("pause");
	return 0;
}

静态成员函数,静态成员函数只能访问静态成员变量。
示例代码:

class Person
{public:
	//静态成员函数特点:
	//1 程序共享一个函数
	//2 静态成员函数只能访问静态成员变量
	static void func()
	{cout<< "func调用"<< endl;
		m_A = 100;
		//m_B = 100; //错误,不可以访问非静态成员变量
	}
	static int m_A; //静态成员变量
	int m_B; //
private:
	//静态成员函数也是有访问权限的
	static void func2()
	{cout<< "func2调用"<< endl;
	}
};
int Person::m_A = 10;
void test01()
{//静态成员变量两种访问方式
	//1、通过对象
	Person p1;
	p1.func();
	//2、通过类名
	Person::func();
	//Person::func2(); //私有权限访问不到
}
int main() 
{test01();
	system("pause");
	return 0;
}
四、类成员储存方式

在C++中,类中的静态成员变量和静态成员函数都不占用对象空间;普通函数也不占用对象空间,所有函数共享一个函数实例。所以只有非静态成员变量才属于类的对象上。
示例代码:

class Person 
{public:
	Person() 
	{mA = 0;
	}
	//非静态成员变量占对象空间
	int mA;
	//静态成员变量不占对象空间
	static int mB;
	//函数也不占对象空间,所有函数共享一个函数实例
	void func() 
	{cout<< "mA:"<< this->mA<< endl;
	}
	//静态成员函数也不占对象空间
	static void sfunc() 
	{}
};
int main() 
{cout<< sizeof(Person)<< endl;
	system("pause");
	return 0;
}
五、this指针

C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针是隐含每一个非静态成员函数内的一种指针。
this指针不需要定义,直接使用即可。

this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this

代码示例:

#includeusing namespace std;

class Person
{public:
	//当形参和成员变量同名时,可用this指针来区分
	Person(int age)
	{this->age= age;
	}
	// 在类的非静态成员函数中返回对象本身,实现相加操作
	Person& PersonAdd(Person &p)
	{this->age+= p.age;
		return *this;
	}
	int age;
};

int main()
{Person p1(10);
	Person p2(10);

	p2.PersonAdd(p1).PersonAdd(p1).PersonAdd(p1).PersonAdd(p1).PersonAdd(p1);

	cout<< p2.age<< endl;

	system("pause");
	return 0;
}
六、const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

代码示例:

#includeusing namespace std;

class Person
{public:
	//定义一个常函数
	void fun1() const
	{//this->m_A = 1;//错误,常函数内不可以修改成员属性
		this->m_B = 10; //成员属性声明时加关键字mutable后,在常函数中依然可以修改
	}
	//定义一个普通函数
	void fun2()
	{}

	int m_A;
	mutable int m_B;
};
//常函数示例
void test1()
{Person p;//普通对象可调用常函数
	p.fun1();
}
//常对象示例
void test2()
{const Person p;//定义一个常对象
	p.fun1();//常对象调用常函数
	//p.m_A = 10;//错误,常对象不能修改成员变量的值,但是可以访问
	//p.fun2();//错误,常对象只能调用常函数
	p.m_B = 1; //常对象可以修改mutable修饰成员变量

}

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网页题目:C++学习笔记——类和对象-创新互联
标题URL:http://ybzwz.com/article/cscscj.html