C++学习笔记----类和对象

本文详细介绍了C++的面向对象特性,包括封装、继承和多态。从封装的意义、struct与class的区别、成员属性的访问权限,到对象的初始化和清理(构造函数、析构函数、拷贝构造函数等),再到C++对象模型、this指针的概念,以及友元、运算符重载。此外,文章还深入探讨了继承的基本语法、多态的概念及其应用,如计算器类、饮品制作等实际案例,强调了多态在软件设计中的重要性。
摘要由CSDN通过智能技术生成

目录

6.1  封装

6.1.1  封装的意义

6.1.2  struct和class的区别

6.1.3  将成员属性设为私有

设计案例1:立方体类

设计案例2:点和圆的关系

6.2  对象的初始化和清理

6.2.1  构造函数

6.2.2  析构函数

6.2.3  拷贝构造函数调用时机

6.2.4  构造函数调用规则

6.2.5  深拷贝与浅拷贝

6.2.6  初始化列表

6.2.7  类对象作为类的成员

6.2.8  静态成员

6.3  C++对象模型和this指针

6.3.1  成员变量和成员函数分开存储

6.3.2  this指针的概念

6.3.3  空指针访问成员函数

6.3.4  const修饰成员函数

6.4  友元

6.4.1  全局函数做友元

6.4.2  类做友元

6.4.3  成员函数做友元 

6.5  运算符重载

6.5.1  加号运算符重载

6.5.2  左移运算符(<<)的重载

6.5.3  递增运算符的重载

6.5.4  赋值运算符重载

6.5.5  关系运算符的重载

6.5.6  函数调用运算符()重载

6.6  继承

6.6.1  继承的基本语法

6.6.2  继承的方式

6.6.3  继承中的对象模型

6.6.4  继承中构造和析构顺序

6.6.5  继承中同名成员的处理方式

6.6.6  继承同名静态成员处理方式

6.6.7  多继承语法

6.6.8  菱形继承

6.7  多态

6.7.1  多态的基本概念

6.7.2  多态案例----计算器类

6.7.3  纯虚函数和抽象类

6.7.4  多态案例二----制作饮品

6.7.5  虚析构和纯虚析构

6.7.6  多态案例三----电脑组装


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

6.1  封装

6.1.1  封装的意义

         1. 将属性和行为作为一个整体。(放在一个class里面)
         2. 将属性和行为加以权限控制。
              public公共权限:类内外都可以访问
              protected保护权限: 类外不可以访问
              private私有权限: 类外不可以访问

//定义一个圆类
#define PI 3.14
//class 定义一个类 circle是类的名字
class circle
{
	//访问权限:公共权限
public:
	//属性
	int r;
	//行为
	double circumference( )
	{
		return r * PI * 2;
	}
};
int main()
{
	circle c1;//创建具体的圆(对象)(实例化)
	c1.r = 10;//给具体的圆的属性赋值
	cout << "圆的周长为:" << c1.circumference() << endl;
	return 0;
}

6.1.2  struct和class的区别

        struct默认权限为: 共有  public
        class默认权限为:   私有  private

6.1.3  将成员属性设为私有

优点:

         ①将成员属性设为私有,可以自己控制读写的权限。
         ②对于写权限,可以检测数据的有效性。

class person
{
private:
	string name;//可读写
	int age;//只读
	string lover;//只写
public:
	void SetName(string s)
	{
		name = s;
	}
	string GetName()
	{
		return name;
	}
	int GetAge()
	{
		age = 18;
		return age;
	}
	void SetLover(string s)
	{
		lover = s;
	}
};
int main()
{
	person p1;
	p1.SetName("xiyang");
	p1.SetLover("2A");
	cout << "姓名为:" << p1.GetName() << endl;
	cout << "年龄为:" << p1.GetAge() << endl;
	return 0;
}

设计案例1:立方体类

/*
要求:
1.设计一个立方体类
2.求出立方体的面积和体积
3.分别用全局函数和成员函数判断两个立方体是否相等
*/

class cube
{
private:
	//属性
	int L;
	int W;
	int H;
public:
	//行为
	//设置 获取长,宽,高
	void SetL(int a)
	{
		L = a;
	}
	int GetL()
	{
		return L;
	}
	void SetW(int a)
	{
		W = a;
	}
	int GetW()
	{
		return W;
	}
	void SetH(int a)
	{
		H = a;
	}
	int GetH()
	{
		return H;
	}
	//获得面积
	int S()
	{
		return 2 * ((L * W) + (L * H) + (W * H));
	}
	//获得体积
	int V()
	{
		return L * W * H;
	}
	//成员函数判断
	bool isSameByClass(cube& c)
	{
		if (c.GetL() == L && c.GetW() ==W && c.GetH() == H)
			return true;
		else
			return false;
	}

};
//全局函数判断
bool isSame(cube& c1, cube& c2)
{
	if (c1.GetL() == c2.GetL() && c1.GetW() == c2.GetW() && c1.GetH() == c2.GetH())
		return true;
	else
		return false;
}
int main()
{
	cube c1,c2;
	c1.SetL(10);
	c1.SetW(10);
	c1.SetH(10);
	c2.SetL(10);
	c2.SetW(10);
	c2.SetH(10);
	cout << "第一个立方体的面积为:" << c1.S() << endl;
	cout << "第一个立方体的体积为:" << c1.V() << endl;
	bool ret1 = isSame(c1, c2);
	if (ret1)
	{
		cout << "全局函数判断c1 c2相等" << endl;
	}
	else
		cout << "全局函数判断c1 c2不相等" << endl;

	bool ret2 = c1.isSameByClass(c2);
	if (ret2)
	{
		cout << "成员函数判断c1 c2相等" << endl;
	}
	else
		cout << "成员函数判断c1 c2不相等" << endl;
	return 0;
}

设计案例2:点和圆的关系

源.cpp

#include<iostream>
using namespace std;
#include"point.h"
#include"circle.h"
void IsInCircle(Circle &c,Point &p)
{
	int distance =
		(c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
		(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
	int rdistance = c.getR() * c.getR();
	if (distance == rdistance)
		cout << "点在圆上"<<endl;
	else if (distance > rdistance)
		cout << "点在圆外"<<endl;
	else
		cout << "点在圆内"<<endl;
}
int main()
{
	Circle c;
	Point center;
	Point q;
	center.setX(10);
	center.setY(10);
	q.setX(10);
	q.setY(10);
	c.setCenter(center);
	c.setR(10);
	IsInCircle(c, q);
	return 0;
}

circle.h

#pragma once
#include<iostream>
using namespace std;
#include"point.h"

class Circle {
public:
	void setR(int r);
	int getR();
	void setCenter(Point center);
	Point getCenter();
private:
	int m_R;
	Point m_Center;
};

circle.cpp

#include"circle.h"

void Circle::setR(int r) {
	m_R = r;
	}
int Circle::getR() {
	return m_R;
	}
void Circle::setCenter(Point center)
{
	m_Center = center;
	}
Point Circle::getCenter() {
	return m_Center;
	}

point.h

#pragma once
#include<iostream>
using namespace std;

class Point {
public:
	void setX(int x);
	int getX();
	void setY(int y);
	int getY();
private:
	int m_X;//д
	int m_Y;//д
};

point.cpp

#include"point.h"

void Point::setX(int x)
{
	m_X = x;
}
int Point::getX() {
	return m_X;
}
void Point::setY(int y) {
	m_Y = y;
}
int Point::getY() {
	return m_Y;
}

6.2  对象的初始化和清理

        C++利用构造函数析构函数解决了对象的初始化和清理。对象的初始化和清理工作是编译器强制要求我们做的事情,因此就算我们不提供构造和析构,编译器也会提供,只不过编译器提供的是构造函数和析构函数的空实现。

6.2.1  构造函数

        定义:主要作用在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
        语法类名 () { }

        注意:①没有返回值,不用写void。

                   ②函数名与类名相同。

                   ③构造函数可以有参数,可以发生重载。

                   ④创建对象时,构造函数会自动调用,并且只调用一次。

        分类:

                按参数分类:有参构造和无参构造(默认构造)

                按类型分类:普通构造和拷贝构造

        调用方式:

                括号法、显示法、隐式转换法

//构造的分类和调用
class person
{
public:
	//无参(普通构造)(默认构造)
	person()
	{
		cout << "无参构造函数调用" << endl;
	}
	//有参(普通构造)
	person(int a)
	{
		age = a;
		cout << "有参构造函数调用" << endl;
	}
	//拷贝构造函数
	person(const person& p)   //加const作用,拷贝之后防止本体被修改
	{
		age = p.age;//克隆数据
		cout << "拷贝构造函数的调用" << endl;
	}
	int age;
};
int main()
{
	//括号法
	person p1;//不能加(),加了()编译器会认为是一个函数声明,在一个函数体里可以声明另一个函数
	person p2(10); //p2的年龄初始化为10
	person p3(p2);

	//显示法
	person p4 = person();
	person p5 = person(10);
	person p6 = person(p5);
	//person()为匿名对象,没有名字,但创建了对象,特点:当前行执行结束后系统就会回收掉匿名对象
	//不要用拷贝构造函数初始化匿名对象,如person(p3),等价于person p3

	//隐式转换法
	person p7 = 10;//转换为:person p7=person(10)
}

6.2.2  析构函数

        定义:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
        语法~类名 () { }

        注意:①没有返回值,不写void

                  ②函数名和类名相同,在名称前加~

                  ③析构函数不可以有参数,不可以发生重载

                  ④对象在销毁前会自动调用析构函数,并且只会调用一次

//构造函数和析构函数例子
class person
{
public:
	person()
	{
		cout << "构造函数的调用" << endl;
	}
	~person()
	{
		cout << "析构函数的调用" << endl;
	}
};
void test()
{
	person P;
}
int main()
{
	test();
	return 0;
}

6.2.3  拷贝构造函数调用时机

        C++中拷贝函数调用一般有三种情况:
                 ①使用一个已创建完毕的对象来初始化一个新对象。
                 ②值传递的方式给函数参数传值。
                 ③以值的方式返回局部对象。

class person
{
public:
	person()
	{
		cout << "默认构造函数的调用" << endl;
	}
	person(int a)
	{
		age = a;
		cout << "默认构造函数的调用" << endl;
	}
	person(const person& p)
	{
		age = p.age;//克隆数据
		cout << "拷贝构造函数的调用" << endl;
	}
	int  show()
	{
		return age;
	}
private:
	int age;
};
void test1(person p)
{
}
person test2()
{
	person p;
	return p;
}
int main()
{
	//使用一个已创建完毕的对象来初始化一个新对象
	person p1(20);
	person p2(p1);
	cout << "p2的年龄为:" << p2.show() << endl;

	//值传递的方式给函数参数传值,拷贝一份临时副本作为形参,改变临时副本的值不影响实参
	person p3;
	test1(p3);
	
	//以值的方式返回局部对象,return返回时返回的不是局部对象,而是拷贝一个新对象返回
	test2();
	return 0;
}

6.2.4  构造函数调用规则

        创建一个类,C++至少给每一个类添加4个函数:

                1、默认构造(空实现)

                2、析构函数(空实现)

                3、拷贝构造(值拷贝)

                4、赋值运算符Operator=对属性进行值拷贝

        ①如果用户定义一个有参构造函数,C++不会提供默认构造函数,但是会提供拷贝构造函数。
        ②如果用户定义一个拷贝构造函数,C++不会提供别的构造函数。

//eg.①如果用户定义一个有参构造函数,C++不会提供默认构造函数,但是会提供拷贝构造函数
class person
{
public:
	person(int a)
	{
		age = a;
		cout << "默认构造函数的调用" << endl;
	}
	int  show()
	{
		return age;
	}
private:
	int age;
};
int main()
{
	person p1;//err
	person p2(18);
	person p3(p2);//拷贝构造函数
	cout << "p2的年龄为:" << p2.show() << endl;
	return 0;
}
//②如果用户定义一个拷贝构造函数,C++不会提供别的构造函数
class person
{
public:
	person(const person& p)
	{
		age = p.age;//克隆数据
		cout << "拷贝构造函数的调用" << endl;
	}
	int  show()
	{
		return age;
	}
private:
	int age;
};
int main()
{
	person p1;//err
	person p2(18);//err
	person p3(p1);
	cout << "p2的年龄为:" << p2.show() << endl;
	return 0;
}

6.2.5  深拷贝与浅拷贝

        浅拷贝:简单的赋值拷贝。

        深拷贝:在堆区重新申请空间,进行拷贝。

        浅拷贝存在的问题:属性有在堆区开辟的,拷贝之后两个类成员堆区属性都指向同一个地址,新拷贝成员执行析构操作之

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值