C++核心编程(黑马笔记)

C++核心编程(面向对象)

内存分区模型

C++执行时,内存大方向划分为4个区域

  • 代码区:存放函数体的二进制代码,由操作系统管理
  • 全局区:存放全局变量和静态变量以及常量
  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
  • 堆区:由程序员分配和释放,如果程序员不释放,程序结束时由操作系统回收

C++核心编程(黑马笔记)_第1张图片

程序运行前

程序编译后,生成了exe,未执行程序前

代码区:

​ 存放CPU执行的机器指令

​ **特点:**共享的:频繁执行代码,只需保存一份

​ 只读的:防止程序意外修改

全局区:

​ 存放全局变量和静态变量

​ 包含常量区:存放字符串常量和其他常量

​ 该区域的数据在程序结束后被操作系统释放

示例:

#include 

using namespace std;

int g_a = 1;
int g_b = 1;

const int g_c = 4;
const int g_d = 4;

int main() {
	int a = 2;
	int b = 2;

	static int s_a = 3;
	static int s_b = 3;

	cout << "局部变量a " << (int)&a << endl;
	cout << "局部变量b " << (int)&b << endl;

	cout << "全局变量a " << (int)&g_a << endl;
	cout << "全局变量b " << (int)&g_b << endl;

	cout << "静态变量a " << (int)&s_a << endl;
	cout << "静态变量b " << (int)&s_b << endl;

	cout << "字符串常量" << (int)&"hello" << endl;

	cout << "全局常量c " << (int)&g_c << endl;
	cout << "全局常量d " << (int)&g_d << endl;

	const int c = 5;
	const int d = 5;

	cout << "局部常量c " << (int)&c << endl;
	cout << "局部常量d " << (int)&d << endl;

	system("pause");

	return 0;
}

程序运行后

栈区:

​ 编译器自动分配释放,存放函数的参数值,局部变量等

​ 注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

示例:

# include 

using namespace std;

int* func() {
	int a = 100;
	return &a;
}

int main() {

	int* p = func();
	cout << *p << endl;
	cout << *p << endl;
	cout << *p << endl;

	system("pause");
	return 0;
}

注意 VS2022(64位)地址一直保留

堆区:

​ 由程序员分配和释放,如果程序员不释放,程序结束时由操作系统回收

​ 主要利用new在堆区开辟内存

示例:

# include 

using namespace std;

int* func() {
	int* p = new int(10);
	return p;
}

int main() {
	// 指针本质上也是局部变量,放在栈上,指针保存的数据放在堆区
	int* p = func();
	cout << *p << endl;
	cout << *p << endl;

	system("pause");
	return 0;
}

new

  • new操作符在堆区开辟数据
  • 手动释放使用delete
  • new的数据返回对应类型的指针

示例:

# include 

using namespace std;

int* func() {
	int* p = new int(10);
	return p;
}

void test01() {
	int* p = func();
	cout << *p << endl;
	cout << *p << endl;
	delete(p);
	//cout << *p << endl;
}

void test02() {
	int* arr = new int[10];
	for (int i = 0; i < 10; i++) {
		arr[i] = i;
	}
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << endl;
	}
	delete[] arr;
}

int main() {

	test01();
	test02();

	system("pause");
	return 0;
}

引用

基本使用

  • 给变量起别名
  • 数据类型 &别名 = 原名
  • 引用必须初始化
  • 一旦初始化,就不可更改

示例:

# include 

using namespace std;


int main() {
	int a = 10;
	int& b = a;

	cout << a << endl;
	cout << b << endl;

	b = 100;
	cout << a << endl;
	cout << b << endl;

	int c = 20;
	b = c;

	cout << a << endl;
	cout << b << endl;
	cout << c << endl;

	system("pause");
	return 0;
}

函数

  • 引用做函数参数

  • 引用做函数返回值

  • 不要返回局部变量的引用

  • 函数的调用可以作为左值

示例:

# include 

using namespace std;

void swap(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

int& test01() {
	int a = 10;
	return a;
}

int& test02() {
	static int a = 90;
	return a;
}

int main() {
	int a = 10;
	int b = 20;
	swap(a, b);
	cout << a << endl;
	cout << b << endl;

	int& ref1 = test01();
	cout << ref1 << endl;
	cout << ref1 << endl;

	int& ref2 = test02();
	cout << ref2 << endl;
	cout << ref2 << endl;
	test02() = 190;
	cout << ref2 << endl;
	cout << ref2 << endl;

	system("pause");
	return 0;
}

本质

本质上是指针常量

int& ref = a 相当于 int* const ref = &a

ref = 20 相当于 *ref = 20


常量引用

**作用:**常量引用主要用来修饰形参,防止误操作

在函数形参列表中,可以加const修饰形参,防止形参改变实参

示例:

# include 

using namespace std;

void show(const int& val) {
	cout << val << endl;
}

int main() {
	const int& ref = 10;// 相当于 int temp = 10; const int& ref = temp;
	// 加上 const 变成只读 不可修改
	int a = 100;
	show(a);

	system("pause");
	return 0;
}

函数高级

默认参数

语法:返回值类型 函数名 (参数 默认值)

注意:

  • 如果某个位置有了默认参数,从这个位置往后,从左往右都必须有默认值
  • 函数声明有了默认参数,函数实现不能有默认参数(只能有一个有默认参数)

示例:

# include 

using namespace std;

int sum(int a, int b = 20, int c = 30) {
	return a + b + c;
}

int main() {
	cout << sum(10) << endl;
	cout << sum(10, 30) << endl;

	system("pause");
	return 0;
}

占位参数

语法:返回值类型 函数名 (数据类型){}

示例:

# include 

using namespace std;

int sum(int a, int) {
	return a;
}

int main() {
	cout << sum(10, 30) << endl;

	system("pause");
	return 0;
}

函数重载

**作用:**函数名可以相同,提高复用性

满足条件:

  • 同一个作用域
  • 函数名称相同
  • 函数参数类型不同或者个数不同或者顺序不同

**注意:**函数重载的返回值不可以作为函数重载的条件

示例:

# include 

using namespace std;

void sum() {
	cout << "aaa" << endl;
}

void sum(int a) {
	cout << "int" << endl;
}

void sum(double a) {
	cout << "double" << endl;
}

void sum(double a, int b) {
	cout << "double,int" << endl;
}

void sum(int a, double b) {
	cout << "int,double" << endl;
}
//注意事项
//int sum(int a, double b) {
//	cout << "int,double" << endl;
//}

int main() {
	sum();
	sum(10);
	sum(10.0);
	sum(3.14, 10);
	sum(10, 3.13);

	system("pause");
	return 0;
}

注意事项:

# include 
using namespace std;
//引用作为重载的条件
void func(int& a) {
	cout << "void func(int& a)" << endl;
}

void func(const int& a) {
	cout << "void func(const int& a)" << endl;
}
//函数重载碰到默认参数
void func2(int a, int b = 10) {
	cout << "a,b" << endl;
}

void func2(int a) {
	cout << "a" << endl;
}

int main() {
	int a;
	func(a);
	func(10);

	//func2(10);

	system("pause");
	return 0;
}

类和对象

封装

意义:

  • 将属性和行为作为一个整体
  • 将属性和行为加以权限控制

示例:

# include 
using namespace std;

class Circle{
public:
	//属性
	int r;
	//行为
	double func() {
		return 2 * 3.14 * r;
	}
	void setR(int R) {
		r = R;
	}
};

int main() {
	Circle c;
	c.r = 10;
	cout << c.func();
	return 0;
}

访问权限:

public 类内可以访问 类外可以访问
protected 类内可以访问 类外不可访问 可以访问父类的保护内容
private 类内可以访问 类外不可访问 不可以访问父类的私有内容

示例:

# include 
# include 
using namespace std;

class Person{
public:
	string name;
protected:
	string car;
private:
	string password;
};

int main() {
	Person nb;
	nb.name = "nb";
	//nb.car;
	//nb.password;
	cout << nb.name;
	return 0;
}

struct与class的区别:

  • struct默认为public
  • class默认为private

成员属性设置为私有:

  • 自己控制读写权限
  • 检测数据有效性

示例:

# include 
# include 
using namespace std;
class Person{
public:
	void setname(string name) {
		m_name = name;
	}

	string getname() {
		return m_name;
	}

	void setage(int age) {
		if (age < 0 || age > 160) {
			cout << "error";
			return;
		}
		m_age = age;
	}

	int getage() {
		return m_age;
	}

	void setid(int id) {
		m_id = id;
	}
private:
	string m_name;
	int m_age = 8;
	int m_id = 1;
};
int main() {
	Person p;
	p.setname("王小明");
	cout << p.getname() << " " << p.getage() << endl;
	return 0;
}

对象的初始化和清理

构造函数和析构函数:

  • 构造函数:创建对象时为对象的成员赋值,由编译器自动调用
  • 析构函数:对象销毁前系统自动调用,执行清理工作

我们不提供析构和构造的话,编译器提供的是空实现。

构造函数语法:类名(){}

析构函数语法:~类名(){}

相同点:

  • 没有返回值也不写void
  • 函数名称与类名相同
  • 无需手动调用,并且只会调用一次

不同点:

  • 构造函数可以有参数,可以发生重载
  • 析构函数不可以有参数,不可以发生重载
# include 
using namespace std;

class Person{
public:
	Person() {
		cout << "1" << endl;
	}
	~Person() {
		cout << "2" << endl;
	}
};

void test01() {
	Person p;
}

int main() {
	//test01();
	Person p;
	system("pause");
	return 0;
}

构造函数的分类和调用:

两种分类方式:

  • 参数:有参构造和无参构造
  • 类型:普通构造和拷贝构造

三种调用方式:

  • 括号法
  • 显示法
  • 隐式转换法
# include 
using namespace std;

class Person{
public:
	Person() {
		cout << "无参构造" << endl;
	}
	Person(int a) {
		age = a;
		cout << "有参构造" << endl;
	}
	Person(const Person& p) {
		age = p.age;
		cout << "拷贝构造" << endl;
	}
	~Person() {
		cout << "析构" << endl;
	}
	int age;
};

void test01() {
	//括号法
	//Person p1;
	//Person p2(10);
	//Person p3(p2);
	//注意:
	//调用默认构造函数时,不要加(),编译器会认为是一个函数的声明

	//cout << "p2年龄为:" << p2.age << endl;
	//cout << "p3年龄为:" << p3.age << endl;

	//显示法
	Person p1;
	Person p2 = Person(10);
	Person p3 = Person(p2);
	//Person(10) 匿名对象 当前行结束 系统自动回收
	//Person(p2) 不能利用拷贝构造函数 初始化匿名对象 
	//			编译器会认为 Person (p3) 相当于 Person p3

	//隐式转换
	Person p4 = 20; // 相当于 Person p4 = Person(20)
	Person p5 = p4;
}

int main() {
	test01();
	system("pause");
	return 0;
}

拷贝构造函数的调用时机:

三种情况:

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

class Person{
public:
	Person() {
		cout << "无参构造" << endl;
	}
	Person(int a) {
		age = a;
		cout << "有参构造" << endl;
	}
	Person(const Person& p) {
		age = p.age;
		cout << "拷贝构造" << endl;
	}
	~Person() {
		cout << "析构" << endl;
	}
	int age;
};

//使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
	
	Person p1(20);
	Person p2(p1);
	cout << "p2年龄为:" << p2.age << endl;
}

//值传递的方式给函数参数传值
void doWork02(Person p) {

}

void test02() {
	Person p;
	doWork02(p);
}

//值方式返回局部对象
Person doWork03() {
	Person p1;
	return p1;
}

void test03() {
	Person p = doWork03();
}

int main() {
	test03();
	system("pause");
	return 0;
}

构造函数调用规则:

默认情况下,C++编译器至少给一个类添加3个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,拷贝属性值

调用规则:

  • 如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,C++不会再提供其他构造函数
# include 
using namespace std;

class Person{
public:
	//Person() {
	//	cout << "无参构造" << endl;
	//}
	Person(int a) {
		age = a;
		cout << "有参构造" << endl;
	}
	//Person(const Person& p) {
	//	age = p.age;
	//	cout << "拷贝构造" << endl;
	//}
	~Person() {
		cout << "析构" << endl;
	}
	int age;
};

//void test01() {
//	Person p1;
//	p1.age = 10;
//	Person p2(p1);
//	cout << "p2年龄为:" << p2.age << endl;
//}

//如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造
void test02() {
	Person p(28);
	Person p2(p);
	cout << "p2年龄为:" << p2.age << endl;
}

int main() {
	test02();
	system("pause");
	return 0;
}

深拷贝与浅拷贝:

  • 浅拷贝:简单赋值拷贝操作
  • 深拷贝:堆区重新申请空间,进行拷贝
# include 
using namespace std;

class Person{
public:
	Person() {
		cout << "无参构造" << endl;
	}
	Person(int a,int h) {
		age = a;
		height = new int(h);
		cout << "有参构造" << endl;
	}
	Person(const Person& p) {
		age = p.age;
		//height = p.height; // 编译器浅拷贝
		height = new int(*p.height);
		cout << "拷贝构造" << endl;
	}
	~Person() {
		if (height != NULL) {
			delete height;
			height = NULL;
		}
		cout << "析构" << endl;
	}
	int age;
	int* height;
};

void test01() {
	Person p1(18, 180);
	cout << "p1年龄为:" << p1.age << " p1身高为:" << *p1.height << endl;
	Person p2(p1);
	cout << "p2年龄为:" << p2.age << " p2身高为:" << *p2.height << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

初始化列表:

语法:构造函数(): 属性1(值1),属性2(值2) ...{}

# include 
using namespace std;

class Person{
public:
	Person(int pa, int pb, int pc) : a(pa), b(pb), c(pc) {

	}
	int a;
	int b;
	int c;
};

void test01() {
	Person p(10, 20, 30);
	cout << p.a << " " << p.b << " " << p.c << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

对象成员:

class A {}
class B {
    A a;
}

示例:顺序:手机构造->人构造->人析构->手机析构

# include 
# include 
using namespace std;

class Phone {
public:
	Phone(string name) {
		m_Pname = name;
		cout << "手机构造" << endl;
	}
	~Phone() {
		cout << "手机析构" << endl;
	}
	string m_Pname;
};

class Person{
public:
	Person(string name, string Pname) : m_name(name), m_phone(Pname) {
		cout << "人构造" << endl;
	}
	~Person() {
		cout << "人析构" << endl;
	}
	string m_name;
	Phone m_phone;
};

void test01() {
	Person p("张三", "苹果");
}

int main() {
	test01();
	system("pause");
	return 0;
}

静态成员:

静态成员变量:

  • 所有对象共享一份数据
  • 编译阶段分配内存
  • 类内声明,类外初始化

静态成员函数:

  • 所有对象共享同一个函数
  • 只能访问静态成员变量

示例1:

# include 
# include 
using namespace std;

class Person{
public:
	static int a;
private:
	static int b;
};

int Person::a = 10;
int Person::b = 20;

void test01() {
	Person p1;
	cout << p1.a << endl;
	Person p2;
	p2.a = 20;
	//两种访问方式
	cout << p1.a << endl;
	cout << Person::a << endl;
	//cout << Person::b << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

示例2:

# include 
# include 
using namespace std;

class Person{
public:
	static void func() {
		a = 100;
		//b = 200; 可能有多个对象包含不同的b 不知道修改哪个b
		cout << "static void func调用" << endl;
	}
	int b;
	static int a;
};

int Person::a = 1000;

void test01() {
	Person p1;
	p1.func();
	Person::func();
}

int main() {
	test01();
	system("pause");
	return 0;
}

C++对象模型和this指针

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

# include 
# include 
using namespace std;

class Person {
	static int a; // 不属于类对象
	int b; // 属于类对象
	void func(){} // 不属于类对象
	static void fun(){} //不属于类对象
};

int Person::a = 1;

void test01() {
	//空对象sizeof为1
	Person p;
	cout << sizeof(p) << endl; 
}

int main() {
	test01();
	system("pause");
	return 0;
}

this指针

this指针指向被调用的成员函数所属的对象

this指针是隐含每一个非静态成员函数内的一种指针

this指针不需要定义,直接使用即可

用途:

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

class Person {
public:
	int age;
	Person(int age) {
		this->age = age;
	}

	//返回Person 值传递调用拷贝构造函数 创建一个新对象 p2-p2'-p2''-p2'''
	Person& PersonAddAge(Person& p) {
		this->age += p.age;
		return *this;
	}
};

void test01() {
	Person p1(10);
	Person p2(10);
	p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
	cout << p2.age << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

空指针访问成员函数:

# include 
# include 
using namespace std;

class Person {
public:
	void show1() {
		cout << "1" << endl;
	}

	void show2() {
		if (this == NULL) {
			return;
		}
		cout << this->b << endl;
	}

	int b;
};

void test01() {
	Person* p = NULL;
	p->show1();
	p->show2();
}

int main() {
	test01();
	system("pause");
	return 0;
}

const修饰成员函数:

常函数:

  • 成员函数后加const
  • 不可以修改成员属性
  • 加关键字mutable后,在常函数中可以修改

常对象:

  • 声明对象前加const
  • 只能调用常函数
# include 
# include 
using namespace std;

class Person {
public:
	//相当于 const Person* const this
	void show() const{
		//this 本质是指针常量 指向不可修改 相当于 Person* const this
		//this = NULL; 
		//this->m_a = 10;
		this->m_b = 20;
	}
	void func(){}
	int m_a;
	mutable int m_b;
};

void test01() {
	Person p1;
	p1.show();
	const Person p2;
	//p2.m_a = 10;
	p2.m_b = 90;
	p2.show();
	//p2.func();
}

int main() {
	test01();
	system("pause");
	return 0;
}

友元

目的:让一个函数或者类访问另一个类中私有成员

关键字:friend

三种实现:

  • 全局函数
  • 成员函数

全局函数:

# include 
# include 
using namespace std;

class Building {
	//全局函数做友元
	friend void test01(Building* b);
public:
	Building() {
		this->m_LivingRoom = "客厅";
		this->m_BedRoom = "卧室";
	}
	string m_LivingRoom;
private:
	string m_BedRoom;
};

void test01(Building *b) {
	cout << b->m_LivingRoom << endl;
	cout << b->m_BedRoom << endl;
}

int main() {
	Building b;
	test01(&b);
	system("pause");
	return 0;
}

类:

# include 
# include 
using namespace std;

class Building;

class GoodGay {
public:
	GoodGay();
	void visit();
	Building* building;
};

class Building {
	//类使用友元
	friend class GoodGay;
public:
	Building() {
		this->m_LivingRoom = "客厅";
		this->m_BedRoom = "卧室";
	}
	string m_LivingRoom;
private:
	string m_BedRoom;
};

GoodGay::GoodGay() {
	building = new Building;
}

void GoodGay::visit() {
	cout << building->m_LivingRoom << endl;
	cout << building->m_BedRoom << endl;
}

void test01() {
	GoodGay g;
	g.visit();
}

int main() {
	test01();
	system("pause");
	return 0;
}

成员函数:

# include 
# include 
using namespace std;

class Building;

class GoodGay {
public:
	GoodGay();
	void visit1();
	Building* building;
};

class Building {
	//成员函数使用友元
	friend void GoodGay::visit1();
public:
	Building() {
		this->m_LivingRoom = "客厅";
		this->m_BedRoom = "卧室";
	}
	string m_LivingRoom;
private:
	string m_BedRoom;
};

GoodGay::GoodGay() {
	building = new Building;
}

void GoodGay::visit1() {
	cout << building->m_LivingRoom << endl;
	cout << building->m_BedRoom << endl;
}

void test01() {
	GoodGay g;
	g.visit1();
}

int main() {
	test01();
	system("pause");
	return 0;
}

运算符重载

加法:

# include 
# include 
using namespace std;

class Person {
public:
	Person() {
		this->m_a = 10;
		this->m_b = 20;
	}
	//成员函数重载
	//本质 p3 = p1.operator+(p2)
	//Person operator+(Person& p) {
	//	Person temp;
	//	temp.m_a = p.m_a + this->m_a;
	//	temp.m_b = p.m_b + this->m_b;
	//	return temp;
	//}
	int m_a;
	int m_b;
};

//全局函数重载
//本质 p3 = operator+(p1, p2)
Person operator+(Person& p1, Person& p2) {
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

void test01() {
	Person p1;
	Person p2;
	Person p3 = p1 + p2;
	cout << p3.m_a << endl;
	cout << p3.m_b << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

左移:

# include 
# include 
using namespace std;

class Person {
public:
	Person() {
		this->m_a = 10;
		this->m_b = 20;
	}
	//成员函数无法实现 p.operator << (cout) 相当于 p << cout
	//void operator<<(cout) {
	//
	//}
	int m_a;
	int m_b;
};

//全局函数实现
ostream& operator<<(ostream& cout, Person& p) {
	cout << p.m_a << " " << p.m_b << endl;
	return cout;
}

void test01() {
	Person p;
	cout << p << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

递增:

# include 
# include 
using namespace std;

class Person {
public:
	Person() {
		this->m_a = 10;
	}
	//前置++重载
	Person& operator++() {
		m_a++;
		return *this;
	}
	//后置++重载
	Person operator++(int) {
		Person temp = *this;
		m_a++;
		return temp;
	}
	int m_a;
};

//全局函数实现
ostream& operator<<(ostream& cout, Person p) {
	cout << p.m_a << " " << endl;
	return cout;
}

void test01() {
	Person p;
	cout << ++(++p) << endl;
	cout << p << endl;
}

void test02() {
	Person p;
	cout << (p++) << endl;
	cout << p << endl;
}

int main() {
	test01();
	test02();
	system("pause");
	return 0;
}

赋值:

# include 
# include 
using namespace std;

class Person {
public:
	Person(int a) {
		m_a = new int(a);
	}
	~Person() {
		if (m_a != NULL) {
			delete m_a;
			m_a = NULL;
		}
	}
	Person& operator=(Person &p) {
		//先释放堆区的内存 即20
		if (m_a != NULL) {
			delete m_a;
			m_a = NULL;
		}
		m_a = new int(*p.m_a);
		return *this;
	}
	int *m_a;
};

void test01() {
	Person p1(18);
	Person p2(20);
	Person p3(30);
	p3 = p2 = p1;
	cout << *p1.m_a << endl;
	cout << *p2.m_a << endl;
	cout << *p3.m_a << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

关系:

# include 
# include 
using namespace std;

class Person {
public:
	Person(int a, int b) {
		m_a = a;
		m_b = b;
	}
	bool operator==(Person& p) {
		if (this->m_a == p.m_a && this->m_b == p.m_b) {
			return true;
		}
		return false;
	}
	bool operator!=(Person& p) {
		if (this->m_a == p.m_a && this->m_b == p.m_b) {
			return false;
		}
		return true;
	}
	int m_a;
	int m_b;
};

void test01() {
	Person p1(10, 20);
	Person p2(10, 20);
	if (p1 == p2) {
		cout << "p1 == p2" << endl;
	}
	if (p1 != p2) {
		cout << "p1 != p2" << endl;
	}
}

int main() {
	test01();
	system("pause");
	return 0;
}

函数调用:

# include 
# include 
using namespace std;

class Person {
public:
	Person(int a, int b) {
		m_a = a;
		m_b = b;
	}
	//int operator()(int x, int y) {
	//	return x + y;
	//}
	void operator()(string text) {
		cout << text << endl;
	}
	int m_a;
	int m_b;
};

void test01() {
	//int ans = Person(10, 20)(10, 20);
	//cout << ans << endl;
	Person(10, 20)("hello world");
}

int main() {
	test01();
	system("pause");
	return 0;
}

继承

继承的目的:减少重复的代码

语法:class 子类 : 继承方式 父类

  • 子类也称为派生类
  • 父类也称为基类
# include 
# include 
using namespace std;

class Base {
public:
	void header() {
		cout << "首页 番剧 直播..." << endl;
	}
	void footer() {
		cout << "国创 时尚 动画..." << endl;
	}
};

class Java : public Base {
public:
	void Tool() {
		cout << "Java视频" << endl;
	}
};

class Python : public Base {
public:
	void Tool() {
		cout << "Python视频" << endl;
	}
};

void test01() {
	Java j;
	j.footer();
	j.Tool();
	Python py;
	py.header();
	py.Tool();
}

int main() {
	test01();
	system("pause");
	return 0;
}

继承方式:

C++核心编程(黑马笔记)_第2张图片

# include 
# include 
using namespace std;

class Base {
public:
	int a;
protected:
	int b;
private:
	int c;
};

class Son1 : public Base {
public:
	void change() {
		a = 10;
		b = 20;
		//c = 30;
	}
};

class Son2 : protected Base {
public:
	void change() {
		a = 10;
		b = 20;
		//c = 30;
	}
};

class Son3 : private Base {
public:
	void change() {
		a = 10;
		b = 20;
		//c = 30;
	}
};

class GrandSon3 : private Son3 {
public:
	void change() {
		//a = 10;
		//b = 20;
		//c = 30;
	}
};

void test01() {
	Son1 s1;
	s1.a = 11;
	//s1.b = 21;
	Son2 s2;
	//s2.a = 11;
	//s2.b = 21;
}

int main() {
	test01();
	system("pause");
	return 0;
}

对象模型:

父类中的所有非静态成员属性都会被子类继承下去

# include 
# include 
using namespace std;

class Base {
public:
	int a;
protected:
	int b;
private:
	int c;
};

class Son1 : public Base {
public:
	int d;
};


void test01() {
	Son1 s1;
	cout << sizeof(s1) << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

继承中构造和析构的顺序:

构造和析构的顺序:先进后出

同名成员处理:

  1. 子类对象可以直接访问子类中的同名成员
  2. 子类对象加作用域可以访问到父类同名成员
  3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
# include 
# include 
using namespace std;

class Base {
public:
	int a = 20;
	void func() {
		cout << "base func()" << endl;
	}
	void func(int m) {
		cout << "base func(" << m << ")" << endl;
	}
protected:
	int b;
private:
	int c;
};

class Son1 : public Base {
public:
	Son1() {
		a = 10;
	}
	int a;
	void func() {
		cout << "Son1 func()" << endl;
	}
};


void test01() {
	Son1 s1;
	cout << s1.a << endl;
	cout << s1.Base::a << endl;
	s1.func();
	s1.Base::func();
	s1.Base::func(2);
}

int main() {
	test01();
	system("pause");
	return 0;
}
# include 
# include 
using namespace std;

class Base {
public:
	static int a;
	static void func() {
		cout << "Base func()" << endl;
	}
	static void func(int m) {
		cout << "Base func(" << m << ")" << endl;
	}
};

int Base::a = 10;

class Son1 : public Base {
public:
	static int a;
	static void func() {
		cout << "Son1 func()" << endl;
	}
};

int Son1::a = 20;

void test01() {
	Son1 s;
	cout << s.a << endl;
	cout << s.Base::a << endl;
	cout << Son1::a << endl;
	cout << Son1::Base::a << endl;
	s.func();
	s.Base::func();
	s.Base::func(3);
	Son1::Base::func();
	Son1::Base::func(3);
}

int main() {
	test01();
	system("pause");
	return 0;
}

多继承:

语法:class 子类 : 继承方式 父类1 , 继承方式 父类2...

不建议使用

菱形继承:
C++核心编程(黑马笔记)_第3张图片

# include 
# include 
using namespace std;

class Animal {
public:
	int age;
};

class Sheep : virtual public Animal{};

class Tuo : virtual public Animal{};

class SheepTuo : public Sheep , public Tuo{};

void test01() {
	SheepTuo st;
	st.Sheep::age = 10;
	st.Tuo::age = 9;
	cout << st.Sheep::age << endl;
	cout << st.Tuo::age << endl;
	cout << st.age << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

总结:

  • 菱形继承的问题是子类继承两份相同数据,资源浪费
  • 利用虚继承解决菱形继承问题

多态

基本概念:

多态分为两类:

  • 静态多态:函数重载和运算符重载
  • 动态多态:派生类和虚函数实现

区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
# include 
# include 
using namespace std;

class Animal {
public:
	virtual void Speak() {
		cout << "动物叫" << endl;
	}
};

class Cat : public Animal {
public:
	void Speak() {
		cout << "小猫叫" << endl;
	}
};

class Dog : public Animal {
public:
	void Speak() {
		cout << "小狗叫" << endl;
	}
};

void doSpeak(Animal& animal) {
	animal.Speak();
}

void test01() {
	Cat c;
	doSpeak(c);
	Dog d;
	doSpeak(d);
}

int main() {
	test01();
	system("pause");
	return 0;
}

动态多态满足条件:

  • 有继承关系
  • 子类重写父类的虚函数

动态多态使用:父类指针或引用 执行子类对象


原理:

C++核心编程(黑马笔记)_第4张图片


纯虚函数和抽象类:

纯虚函数语法:virtual 返回值类型 函数名 (参数列表) = 0

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
# include 
# include 
using namespace std;

class MakeDrunk {
public:
	virtual void Boil() = 0 {};
	virtual void Brew() = 0 {};
	virtual void PutInCup() = 0 {};
	virtual void PutSomething() = 0 {};
	void Work() {
		Boil();
		Brew();
		PutInCup();
		PutSomething();
	}
};

class Coffee : public MakeDrunk {
public:
	virtual void Boil() {
		cout << "煮沸农夫山泉" << endl;
	}
	virtual void Brew() {
		cout << "煮咖啡" << endl;
	}
	virtual void PutInCup() {
		cout << "放入杯中" << endl;
	}
	virtual void PutSomething() {
		cout << "放牛奶和糖" << endl;
	}
};

class Tea : public MakeDrunk {
public:
	virtual void Boil() {
		cout << "煮沸自来水" << endl;
	}
	virtual void Brew() {
		cout << "煮茶" << endl;
	}
	virtual void PutInCup() {
		cout << "放入杯中" << endl;
	}
	virtual void PutSomething() {
		cout << "放茶叶" << endl;
	}
};

void doWork(MakeDrunk* md) {
	md->Work();
}

void test01() {
	doWork(new Tea);
	doWork(new Coffee);
}

int main() {
	test01();
	system("pause");
	return 0;
}

虚析构和纯虚析构:

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决方式:父类中的析构函数改为虚析构和纯虚析构

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体函数实现

虚析构和纯虚析构区别:

  • 纯虚析构,属于抽象类,无法实例化对象

虚析构:virtual ~类名(){}

纯虚析构:virtual ~类名() = 0 类名::~类名(){}

# include 
# include 
using namespace std;

class Animal {
public:
	Animal() {
		cout << "animal构造" << endl;
	}
	//virtual ~Animal() {
	//	cout << "animal析构" << endl;
	//}
	virtual ~Animal() = 0;
	virtual void Speak() {
		cout << "动物叫" << endl;
	}
};

Animal::~Animal() {
	cout << "animal析构" << endl;
}

class Cat : public Animal {
public:
	Cat(string name) {
		m_Name = new string(name);
		cout << "cat构造" << endl;
	}
	~Cat() {
		if (m_Name != NULL) {
			cout << "cat析构" << endl;
			delete m_Name;
			m_Name == NULL;
		}
	}
	void Speak() {
		cout << "小猫叫" << endl;
	}
	string* m_Name;
};

void test01() {
	Animal* a = new Cat("Tom");
	a->Speak();
	delete a;
}

int main() {
	test01();
	system("pause");
	return 0;
}

总结:

  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
  2. 如果子类中没有堆区数据,可以不写虚析构或纯虚析构
  3. 拥有纯虚析构函数的类也属于抽象类

文件操作

对文件进行操作需要包含头文件

文件类型:

  1. 文本文件
  2. 二进制文件

操作文件的三大类:

  1. ofstream:写
  2. ifstream:读
  3. fstream:读写

文本文件

写文件:

1.包含头文件

2.创建流对象

3.打开文件

4.写数据

5.关闭文件

打开方式 解释
ios::in 目的是读文件
ios::out 目的是写文件
ios::ate 初始位置:文件尾
ios::app 追加方式写文件
ios::trunc 文件存在先删除,再创建
ios::binary 二进制
# include 
# include 
# include 
using namespace std;

void test01() {
	ofstream os;
	os.open("test.txt", ios::out);
	os << "姓名" << endl;
	os << "性别" << endl;
	os << "年龄" << endl;
	os.close();
}

int main() {
	test01();
	system("pause");
	return 0;
}

C++核心编程(黑马笔记)_第5张图片


读文件:

# include 
# include 
# include 
using namespace std;

void test01() {
	ifstream ifs;
	ifs.open("test.txt", ios::in);
	if (!ifs.is_open()) {
		cout << "error" << endl;
		return;
	}
	//第一种
	//char buf[1024] = { 0 };
	//while (ifs >> buf) {
	//	cout << buf << endl;
	//}
	//第二种
	//char buf[1024] = { 0 };
	//while (ifs.getline(buf, sizeof(buf))) {
	//	cout << buf << endl;
	//}
	//第三种
	//string buf;
	//while (getline(ifs, buf)) {
	//	cout << buf << endl;
	//}
	//第四种
	char c;
	while ((c = ifs.get()) != EOF) {
		cout << c;
	}
	ifs.close();
}

int main() {
	test01();
	system("pause");
	return 0;
}

二进制文件

打开方式指定:ios::binary

写文件:

调用成员函数write

函数原型:ostream& write(const char * buffer, int len)

解释:buffer->内存中一段存储空间 len是读写的字节数

# include 
# include 
# include 
using namespace std;

class Person {
public:
	char m_Name[1024];
	int m_Age;
};

void test01() {
	ofstream ofs("person.txt", ios::out | ios::binary);
	Person p = { "张三", 30 };
	ofs.write((const char*)&p, sizeof(p));
	ofs.close();
}

int main() {
	test01();
	system("pause");
	return 0;
}

C++核心编程(黑马笔记)_第6张图片


读文件:

调用成员函数read

函数原型:istream& read(char * buffer, int len)

解释:buffer->内存中一段存储空间 len是读写的字节数

# include 
# include 
# include 
using namespace std;

class Person {
public:
	char m_Name[1024];
	int m_Age;
};

void test01() {
	ifstream ifs("person.txt", ios::in | ios::binary);
	if (!ifs.is_open()) {
		cout << "error" << endl;
		return;
	}
	Person p;
	ifs.read((char*)&p, sizeof(Person));
	cout << p.m_Name << p.m_Age << endl;
	ifs.close();
}

int main() {
	test01();
	system("pause");
	return 0;
}

你可能感兴趣的:(C++基础,c++,笔记,c语言,开发语言)