6、运算符重载、继承(C++核心语法)

1 关系运算符重载

1.1 对于自定义数据类型,编译器不知道如果进行比较
1.2 重载 == !=号
1.3 bool operator==( Person & p)
1.4 bool operator!=(Person & p)

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class  Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	bool operator==( Person & p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		return false;
	}


	bool operator!=(Person & p)
	{
		return !(this->m_Name == p.m_Name && this->m_Age == p.m_Age);
	}


	string m_Name;
	int m_Age;
};

void test01()
{
	//int a = 10;
	//int b = 20;
	//if (a == b)
	//{
	//	cout << "a == b " << endl;
	//}
	//else
	//{
	//	cout << "a != b " << endl;
	//}

	Person p1("Tom", 18);

	Person p2("Tom", 19);

	if (p1 == p2)
	{
		cout << "p1 == p2 " << endl;
	}	
	else
	{
		cout << "a != b " << endl;
	}


	if (p1 != p2)
	{
		cout << "a != b " << endl;
	}
	else
	{
		cout << "p1 == p2 " << endl;
	}

}


int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

2 函数调用运算符重载

2.1 重载 ()
2.2 使用时候很像函数调用,因此称为仿函数
2.3 void operator()(string text)
2.4 int operator()(int a,int b)
2.5 仿函数写法不固定,比较灵活
2.6 cout << MyAdd()(1, 1) << endl; // 匿名函数对象 特点:当前行执行完立即释放

#define _CRT_SECURE_NO_WARNINGS
	#include<iostream>
	using namespace std;
	#include <string>

	class MyPrint
	{
	public:
		void operator()(string text)
		{
			cout << text << endl;
		}
	};

	void MyPrint2(string str)
	{
		cout << str << endl;
	}

	void test01()
	{
		MyPrint myPrint;
		myPrint("hello world"); // 仿函数  本质是一个对象   函数对象

		MyPrint2("hello world"); //普通函数
	}

	class MyAdd
	{
	public:
		int operator()(int a,int b)
		{
			return a + b;
		}
	};

	void test02()
	{
		MyAdd myAdd;
		cout << myAdd(1, 1) << endl;

		cout << MyAdd()(1, 1) << endl; // 匿名函数对象 特点:当前行执行完立即释放
	}

	int main(){

		//test01();
		test02();

		system("pause");
		return EXIT_SUCCESS;
	}
	

3 不要重载 && 和 ||

3.1 原因是无法实现短路特性
3.2 建议:将<< 和 >>写成全局函数配合友元函数进行重载,其他可重载的符号写到成员即可
3.3 =,[],(),->操作符只能通过成员函数进行重载

4 强化训练-字符串类封装(面试经典题)

4.1 myString类 实现自定义的字符串类
4.2 属性
	4.2.1 char * pString; 维护 在堆区真实开辟的字符数组
	4.2.2 int m_Size; 字符串长度
4.3 行为
	4.3.1 有参构造 MyString(char * str)
	4.3.2 拷贝构造 MyString(const MyString & str);
	4.3.3 析构  ~MyString();
4.4 重载<< 运算符
4.5 重载 >> 运算符
4.6 重载 =   赋值运算
4.7 重载 []  str[0]  按照索引位置设置获取字符
4.8 重载 +  字符串拼接
4.9 重载 == 对比字符串

```cpp
//代码
	//StringMain.cpp
	#define _CRT_SECURE_NO_WARNINGS
	#include<iostream>
	using namespace std;
	//#include <string>
	#include "myString.h"


	void test01()
	{
		MyString str = "abc";

		cout << str << endl;

		cout << "请重新给str赋值:" << endl;

		cin >> str;

		cout << "str 新的值为: " << str << endl;


		MyString str2 = str;

		cout << "str2 = " << str2 << endl;

	}

	void test02()
	{
		MyString str = "abcd";

		MyString str2 = "aaa";

		str2 = str;

		cout << "str2 = " << str2 << endl;

		cout << "str2[0] = " << str2[0] << endl;

		str2[0] = 'z';

		cout << "str2[0]改为z后输出:  " << str2 << endl;


		MyString str3 = "abc";
		MyString str4 = "def";
		MyString str5 = str3 + str4;
		MyString str6 = str5 + "ghe";
		cout << "str5 = " << str5 << endl;
		cout << "str6 = " << str6 << endl;


		if (str5 == str6)
		{
			cout << "str5 == str6" << endl;
		}
		else
		{
			cout << "str5 != str6" << endl;
		}

		if ( str6 == "abcdefghe")
		{
			cout << "str6 = abcdefghe" << endl;
		}
		else
		{
			cout << "str6 != abcdefghe" << endl;
		}



	}


	int main(){
		//test01();
		test02();
		//int a = 10;
		//cin >> a;
		//cout << "a  = " << a << endl;

		system("pause");
		return EXIT_SUCCESS;
	}
	

//myString.h

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

class MyString
{
	//左移运算符友元
	friend ostream& operator<<(ostream & cout, MyString & str);
	//右移运算符 友元
	friend istream&  operator>>(istream & cin, MyString & str);
public:

	//有参构造
	MyString(char  * str);
	//拷贝构造
	MyString(const MyString & str);

	//重载=运算符 

	MyString& operator=(const char * str);
	MyString& operator=(const MyString & str);

	//重载[]运算符
	char& operator[](int index);

	//重载+运算符
	MyString operator+(const char * str);
	MyString operator+(const MyString&str);

	//重载==运算符 
	bool operator==(const char *str);
	bool operator==(const MyString &str);

	//析构
	~MyString();

private:

	char * pString; //维护在堆区开辟的字符数组

	int m_Size; //字符串长度 不统计\0

};

//myString.cpp

#include "myString.h"

	//重载左移运算符
	ostream& operator<<(ostream &cout, MyString & str)
	{
		cout << str.pString;
		return cout;
	}

	//重载左移运算符
	istream& operator>>(istream & cin, MyString & str)
	{
		//先清空原来堆区数据
		if (str.pString)
		{
			delete[] str.pString;
			str.pString = NULL;
		}

		char buf[1024];//开辟临死数组 记录用户输入内容
		cin >> buf;

		str.pString = new char[strlen(buf) + 1];
		strcpy(str.pString,buf);
		str.m_Size = strlen(buf);
		
		//cout << str.pString;
		return cin;
	}

	MyString::MyString(char * str)
	{
		//cout << "MyString有参构造函数调用" << endl;
		this->pString = new char[strlen(str) + 1];
		strcpy(this->pString, str);
		this->m_Size = strlen(str);
	}
	MyString::MyString(const MyString & str)
	{
		//cout << "MyString拷贝构造函数调用" << endl;
		this->pString = new char[strlen(str.pString) + 1];
		strcpy(this->pString, str.pString);
		this->m_Size = strlen(str.pString);
	}
	MyString& MyString::operator=(const char * str)
	{
		//先判断原来堆区释放有内容 如果有就先释放
		if (this->pString!=NULL)
		{
			delete[] this->pString;
			this->pString = NULL;
		}
		this->pString = new char[strlen(str) + 1];
		strcpy(this->pString, str);
		this->m_Size = strlen(str);
		return *this;
	}

	MyString& MyString::operator=(const MyString & str)
	{
		//先判断原来堆区释放有内容 如果有就先释放
		if (this->pString != NULL)
		{
			delete[] this->pString;
			this->pString = NULL;
		}
		this->pString = new char[strlen(str.pString) + 1];
		strcpy(this->pString, str.pString);
		this->m_Size = strlen(str.pString);
		return *this;
	}

	char & MyString::operator[](int index)
	{
		return this->pString[index];
	}

	MyString MyString::operator+(const char * str)
	{
		//计算开辟内存大小
		int newSize = this->m_Size + strlen(str) + 1;

		char * temp = new char[newSize];
		memset(temp, 0, newSize);//清空temp

		strcat(temp, this->pString);
		strcat(temp, str);//字符串拼接

		MyString newString = temp;

		delete[] temp;

		return newString;
	}

	MyString MyString::operator+(const MyString & str)
	{
		//计算开辟内存大小
		int newSize = this->m_Size + strlen(str.pString) + 1;

		char * temp = new char[newSize];
		memset(temp, 0, newSize);//清空temp

		strcat(temp, this->pString);
		strcat(temp, str.pString);//字符串拼接

		MyString newString = temp;

		delete[] temp;

		return newString;
	}

	bool MyString::operator==(const char * str)
	{
		if (strcmp(this->pString,str)==0)
		{
			return true;
		}
		return false;
	}

	bool MyString::operator==(const MyString & str)
	{
		if (strcmp(this->pString, str.pString) == 0)
		{
			return true;
		}
		return false;
	}

	MyString::~MyString()
	{
		if (this->pString!=NULL)
		{
			delete[] this->pString;
			this->pString = NULL;
		}
	}
	

5 继承基本语法

5.1 继承优点:减少重复的代码,提高代码复用性
5.2 // 语法: class 子类 : 继承方式   父类
5.3 // News		子类    派生类
5.4 // BasePage 父类    基类

```cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//class News
//{
//public:
//
//	void header()
//	{
//		cout << "公共的头部" << endl;
//	}
//	void footer()
//	{
//		cout << "公共的底部" << endl;
//	}
//	void leftList()
//	{
//		cout << "公共的左侧列表" << endl;
//	}
//
//	void content()
//	{
//		cout << "新闻播报..." << endl;
//	}
//};
//
//
//class Sport
//{
//public:
//
//	void header()
//	{
//		cout << "公共的头部" << endl;
//	}
//	void footer()
//	{
//		cout << "公共的底部" << endl;
//	}
//	void leftList()
//	{
//		cout << "公共的左侧列表" << endl;
//	}
//
//	void content()
//	{
//		cout << "世界杯赛况..." << endl;
//	}
//};


//利用继承模拟网页
//继承优点: 减少重复的代码,提高代码复用性
class BasePage
{
public:
	void header()
	{
		cout << "公共的头部" << endl;
	}
	void footer()
	{
		cout << "公共的底部" << endl;
	}
	void leftList()
	{
		cout << "公共的左侧列表" << endl;
	}
};
// 语法: class 子类 : 继承方式   父类
// News		子类    派生类
// BasePage 父类    基类
class News : public BasePage
{
public:
	void content()
	{
		cout << "新闻播报..." << endl;
	}
};

class Sport :public BasePage
{
public:
	void content()
	{
		cout << "世界杯..." << endl;
	}

};


void test01()
{
	News news;
	cout << "新闻页面内容如下:" << endl;
	news.header();
	news.footer();
	news.leftList();
	news.content();


	Sport sp;
	cout << "体育页面内容如下:" << endl;
	sp.header();
	sp.footer();
	sp.leftList();
	sp.content();

}


int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

6 继承方式

6.1 公共继承 public
	6.1.1 父类中公共权限(public),子类中变为公共权限(public)
	6.1.2 父类中保护权限(protected),子类中变为保护权限(protected)
	6.1.3 父类中私有权限(private),子类访问不到
6.2 保护继承 protected
	6.2.1 父类中公共权限,子类中变为保护权限(protected)
	6.2.2 父类中保护权限,子类中变为保护权限(protected)
	6.2.3 父类中私有权限(private),子类访问不到
6.3 私有继承 private 
	6.3.1 父类中公共权限,子类中变为私有权限(private)
	6.3.2 父类中保护权限,子类中变为私有权限(private)
	6.3.3 父类中私有权限(private),子类访问不到
#define _CRT_SECURE_NO_WARNINGS
	#include<iostream>
	using namespace std;

	/   公共继承  
	class Base1
	{
	public:
		int m_A;
	protected:
		int m_B;
	private:
		int m_C;
	};

	class Son1 :public Base1
	{
	public:

		void func()
		{
			m_A = 100; //父类中 公共权限 子类中变为  公共权限
			m_B = 100; //父类中 保护权限 子类中变为  保护权限
			//m_C = 100;// 父类中私有成员,子类无法访问
		}
	};

	void test01()
	{
		Son1 s1;
		s1.m_A = 100; //在Son1中 m_A是公共权限  类外可以访问
		//s1.m_B = 100; //在Son1中 m_B是保护权限  类外不可以访问
	}


	/   保护继承  
	class Base2
	{
	public:
		int m_A;
	protected:
		int m_B;
	private:
		int m_C;
	};

	class Son2 : protected Base2
	{
	public:
		void func()
		{
			m_A = 100;//父类中 公共权限 子类中变为  保护权限
			m_B = 100;//父类中 保护权限 子类中变为  保护权限
			//m_C = 100;//父类中私有成员,子类无法访问
		}
	};

	void test01()
	{
		Son2 s;
		//s.m_A = 100;  //子类中 保护权限 无法访问
		//s.m_B = 100;  //子类中 保护权限 无法访问
		//s.m_C = 100; //子类本身没有访问权限
	}


	/   私有继承  
	class Base3
	{
	public:
		int m_A;
	protected:
		int m_B;
	private:
		int m_C;
	};
	class Son3 :private Base3
	{
	public:
		void func()
		{
			m_A = 100;  //父类中 公共权限 子类中变为  私有权限
			m_B = 100;  //父类中 保护权限 子类中变为  私有权限
			//m_C = 100;//父类中私有成员,子类无法访问
		}
	};
	class GrandSon3 :public Son3
	{
	public:
		void func()
		{
			//m_A = 100;//在Son3中 已经变为私有权限,GrandSon3访问不到
			//m_B = 100;
		}
	};
	void test03()
	{
		Son3 s;
		//s.m_A = 100;//在Son3中变为私有权限,类外访问不到
		//s.m_B = 100;//在Son3中变为私有权限,类外访问不到

	}

	int main(){



		system("pause");
		return EXIT_SUCCESS;
	}
	

7 继承中的对象模型

7.1 父类中的私有属性,子类是继承下去了,只不过由编译器给隐藏了,访问不到
7.2 可以利用开发人员工具查看对象模型
7.3 C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts
7.4 打开开发人员命令工具
7.5 跳转盘符 E:
7.6 跳转文件路径  cd到文件路径下
7.7 cl /d1 reportSingleClassLayout类名  文件名
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;  //父类中私有属性,子类访问不到,是由编译器给隐藏了
};

class Son : public Base
{
public:
	int m_D;
};

void test01()
{
	//4  8    12   16
	cout << "size of  Son = " << sizeof(Son) << endl; // 结果为16
}

int main(){

	test01();
	system("pause");
	return EXIT_SUCCESS;
}
			

8 继承中的构造和析构

8.1 先调用父类构造,再调用其他成员构造, 再调用自身构造 ,析构的顺序与构造相反
8.2 利用初始化列表语法 显示调用父类中的其他构造函数
8.3 父类中 (任何的)构造、析构、拷贝构造 、operator= 是不会被子类继承下去的

在C++中,构造函数不会自动继承,只是如果子类没有写构造函数,
那么系统会这个类自动添加一个默认构造函数,是一个空函数体,所以什么也没有做,
接着就会调用父类的构造函数,所以你觉得是继承了父类的构造函数。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base1
{
public:
	Base1()
	{
		cout << "Base1的构造函数调用" << endl;

	}

	~Base1()
	{
		cout << "Base1的析构函数调用" << endl;
	}

};

class Other
{
public:
	Other()
	{
		cout << "Other的构造函数调用" << endl;
	}

	~Other()
	{
		cout << "Other的析构函数调用" << endl;
	}
};

class Son1 :public Base1
{
public:
	Son1()
	{
		cout << "Son1的构造函数调用" << endl;
	}

	~Son1()
	{
		cout << "Son1的析构函数调用" << endl;
	}

	Other other;
};

void test01()
{
	Son1 s; //先调用父类构造,再调用其他成员构造, 再调用自身构造 ,析构的顺序与构造相反
}

class Base2
{
public:
	Base2(int a)
	{
		this->m_A = a;
		cout << "Base2的构造函数调用" << endl;
	}
	int m_A;
};
class Son2 :public Base2
{
public:
	Son2(int a = 1000 ) :Base2(a)  //利用初始化列表语法  显示调用父类中的其他构造函数
	{
		cout << "Son2的构造函数调用" << endl;
	}
};
void test02()
{
	Son2 s;
	cout << s.m_A << endl;
}

//父类中 构造、析构、拷贝构造 、operator=  是不会被子类继承下去的

int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

9 继承中的同名成员处理

9.1 我们可以利用作用域 访问父类中的同名成员
9.2 当子类重新定义了父类中的同名成员函数,子类的成员函数会 隐藏掉父类中所有重载版本的同名成员,可以利用作用域显示指定调用

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base
{
public:
	Base()
	{
		this->m_A = 10;
	}

	void func()
	{
		cout << "Base中的func调用" << endl;
	}

	void func(int a)
	{
		cout << "Base中的func(int)调用" << endl;
	}

	int m_A;
};

class Son :public Base
{
public:

	Son()
	{
		this->m_A = 20;
	}

	void func()
	{
		cout << "Son中的func调用" << endl;
	}

	int m_A;
};




void test01()
{
	Son s1;

	cout << "s1.m_A = " <<  s1.m_A << endl;

	//我们可以利用作用域 访问父类中的同名成员
	cout << "Base中的m_A = " << s1.Base::m_A << endl;
}

void test02()
{
	Son s1;
	s1.func();
	s1.Base::func(10);

	//当子类重新定义了父类中的同名成员函数,子类的成员函数会 隐藏掉父类中所有重载版本的同名成员,可以利用作用域显示指定调用

}


int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

10 继承中的同名 静态成员处理

10.1 结论和 非静态成员 一致
10.2 只不过调用方式有两种
	10.2.1 通过对象
	10.2.2 通过类名
		10.2.2.1 通过类名的方式 访问 父类作用域下的m_A静态成员变量
		10.2.2.2 Son::Base::m_A
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base
{
public:

	static void func()
	{
		cout << "Base中的func调用 " << endl;
	}

	static void func(int a)
	{
		cout << "Base中的func(int a)调用 " << endl;
	}

	static int m_A;

};

int Base::m_A = 10;


class Son :public Base
{
public:

	static void func()
	{
		cout << "Son中的func调用 " << endl;
	}

	static int m_A;
};
int Son::m_A = 20;

void test01()
{
	//1、通过对象访问
	Son s;
	cout << "m_A = " << s.m_A << endl;
	cout << "Base中的m_A = " << s.Base::m_A << endl;

	//2、通过类名访问

	cout << "m_A = " << Son::m_A << endl;
	//通过类名的方式 访问 父类作用域下的m_A静态成员变量
	cout << "Base中的m_A = " <<  Son::Base::m_A << endl;
}


void test02()
{
	//1、通过对象
	Son s;
	s.func();
	s.Base::func();


	//2、通过类名
	Son::func();
	//当子类重定义父类中同名成员函数,子类的成员函数会隐藏掉父类中所有版本,需要加作用域调用
	Son::Base::func(1);
}


int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

11 多继承基本语法

11.1 class 子类 : 继承方式  父类1 , 继承方式 父类2 
11.2 当多继承的两个父类中有同名成员,需要加作用域区分
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base1
{
public:
	Base1()
	{
		this->m_A = 10;
	}
	int m_A;
};

class Base2
{
public:
	Base2()
	{
		this->m_A = 20;
	}
	int m_A;
};

//多继承
class Son : public Base1, public Base2
{
public:

	int m_C;
	int m_D;
};

void test01()
{
	cout << "sizeof Son = " << sizeof(Son) << endl;

	Son s;
	//当多继承的两个父类中有同名成员,需要加作用域区分
	cout << s.Base1::m_A << endl;
	cout << s.Base2::m_A << endl;
}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

12 菱形继承

12.1 两个类有公共的父类  和共同的子类 ,发生菱形继承
12.2 菱形继承导致数据有两份,浪费资源
12.3 解决方案:利用虚继承可以解决菱形继承问题
12.3.1 class Sheep : virtual public Animal{};
12.4	//当发生虚继承后,sheep和tuo类中 继承了一个  vbptr指针   虚基类指针   指向的是一个 虚基类表  vbtable
12.5	//虚基类表中记录了  偏移量 ,通过偏移量 可以找到唯一的一个m_Age
12.6 利用地址偏移找到 vbtable中的偏移量 并且访问数据
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//动物类
class Animal
{
public:
	int m_Age; // 年龄
};

//Animal称为 虚基类

//羊类
class Sheep : virtual public Animal{};
//驼类
class Tuo : virtual public Animal{};

//羊驼
class SheepTuo : public Sheep, public Tuo
{
};


void test01()
{
	SheepTuo st;

	st.Sheep::m_Age = 10;
	st.Tuo::m_Age = 20;

	cout << "Sheep::m_Age = " << st.Sheep::m_Age << endl;
	cout << "Tuo::m_Age = " << st.Tuo::m_Age << endl;
	cout << "age = " << st.m_Age << endl;

	//当发生虚继承后,sheep和tuo类中 继承了一个  vbptr指针   虚基类指针   指向的是一个 虚基类表  vbtable
	//虚基类表中记录了  偏移量 ,通过偏移量 可以找到唯一的一个m_Age
}


void test02()
{
	SheepTuo st;
	st.m_Age = 10;

	//通过Sheep找到 偏移量
	//*(int *)&st 解引用到了 虚基类表中
	cout << *((int *)*(int *)&st + 1) << endl;

	//通过Tuo 找到偏移量
	cout << *((int *)*((int *)&st + 1) + 1) << endl;

	//通过偏移量  访问m_Age

	cout << "m_Age = " << ((Animal *)((char *)&st + *((int *)*(int *)&st + 1)))->m_Age << endl;

	cout << "m_Age = " << *((int *)((char *)&st + *((int *)*(int *)&st + 1))) << endl;
}

int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值