C++基础笔记(二)函数重载和类

一、C++小案例

1.设计圆类

class 类名{

public 公共权限

设置 成员属性

设置 成员函数

}

使用类 创建对象 实例化对象

类名 对象名

通过对象 来设置属性 调用成员函数

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

const double pi = 3.14;

// 1.	设计一个类,求圆的周长
// 周长公式  2 * pi * r
class Circle //class代表声明一个类 后面紧跟的是类的名称
{
public: //公共权限

//求圆的周长
	//在类里面写函数  成员函数
	double calculateZC()
	{
		return 2 * pi * m_R;
	}

	//设置半径的成员方法
	//成员函数 可以修改成员属性
	void setR(int r)
	{
		m_R = r;
	}

	//半径  成员属性
	int m_R;

};

void test01()
{
	//通过类 来创建一个圆 
	Circle c1; //圆 (对象)
	//c1.m_R = 10; //给这个对象来进行半径的赋值
	//通过成员函数 间接给圆设置半径
	c1.setR(10);

	//输出c1的周长

	cout << "c1的周长为: " << c1.calculateZC() << endl;
}

2.设计学生类

类和对象 关系???

  • 类是对对象的抽象

  • 对象是对类的实例

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

/*
2.	设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓   名和学号
*/

class Student
{
public: //公共权限

	//设置姓名
	void setName(string name)
	{
		m_Name = name;
	}
	//设置学号
	void setId(int id)
	{
		m_Id = id;
	}

	//打印信息
	void showInfo()
	{
		cout << "姓名:" << m_Name << " 学号: " << m_Id << endl;
	}

	string m_Name; //姓名
	int m_Id; //学号

};

void test01()
{
	//创建一个学生 实例化 --  通过类来创建对象的过程
	Student st;
	st.setName("张三");
	st.setId(1);

	//通过st的属性打印了 st信息
	cout << "st的姓名为: " << st.m_Name << " st的学号:" << st.m_Id << endl;
	

	//通过成员函数 来打印st的信息
	st.showInfo();
}


int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

二、内联函数 解决宏缺陷问题

1.宏缺陷

  1. 不加()出现的问题
#define  MyAdd (x,y) x+y

void test01()
{
	int ret = MyAdd(10, 20) *20; //预期结果 600 实际结果 410 = 10 +20*20

	cout << "ret = " << ret << endl;
}
#define  MyAdd(x,y) ((x)+(y))

void test01()
{
	int ret = MyAdd(10, 20) *20; //预期结果 600 ((10)+(20))*20

	cout << "ret = " << ret << endl;
}
  1. ++a出现的问题
#define MyCompare(a,b)  ((a) < (b)) ? (a) :(b)

void test02()
{
	int a = 10;
	int b = 20;

	int ret =  MyCompare(a, b); // 预期结果 10    ((a) < (b)) ? (a) :(b)

	cout << "ret = " << ret << endl;

}
#define MyCompare(a,b)  ((a) < (b)) ? (a) :(b)

void test02()
{
	int a = 10;
	int b = 20;

	int ret =  MyCompare(++a, b); // 预期结果 11    ((++a) < (b)) ? (++a):(b)
								  // 实际结果12    ((++a) < (b)) 此时 a=11
    							  //         (++a):(b) a又执行一次自加,此时 a=12
	cout << "ret = " << ret << endl;

	mycompare(++a, b);

}
  1. 宏定义没有作用域

2.内联函数注意事项

  1. 内联函数是以空间换时间 (内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省去了函数调用时候的压栈,跳转,返回的开销。)
// 类内部的成员函数 默认前面会加inline关键字
inline void func(); //内联函数声明
inline void func() { }; //如果函数实现时候,没有加inline关键字 ,那么这个函数依然不算内联函数
  1. 类内部的成员函数 默认为内联函数,默认前面会加inline关键字

3.内联编译的限制

  1. 以下情况即使加入inline关键字也不会进行内敛编译
    • 不能存在任何形式的循环语句
    • 不能存在任何形式的循环语句
    • 函数体不能过于庞大
    • 不能对函数进行取址操作
  2. 内联仅仅只是给编译器一个建议,编译器不一定会接受这种建议
  3. 如果你没有将函数声明为内联函数,那么编译器也可能将此函数做内联编译。

三、函数参数

C语言中没有默认参数,C也没有 占位参数

1.函数默认参数

  1. 参数可以有默认值
  2. 如果有一个位置有了默认值,那么从这个位置开始,从左往右都必须有默认值
  3. 传入参数 ,如果有参数,就用传入的参数,没有参数就用默认值
void func( int a , int b = 10,int c = 1 )
{
	cout << "a + b + c = " << a + b + c << endl;
}

void test01()
{
	//func();

	func(1,2);

}
  1. 函数声明和实现 只能有一个有默认值
//如果函数声明里面有了 默认参数,那么函数实现时候必须没有
// 函数声明和实现里 只能有一个里有默认参数,不要同时都出现默认参数
void myFunc(int a = 10, int b = 10);//函数声明
void myFunc(int a , int b ){}//函数实现

2.函数占位参数

  1. 如果有了占位参数,函数调用时候必须要提供这个参数 ,但是用不到参数
  2. 占位参数 没有什么大用途,只有后面重载 ++符号才有一点点用
  3. 占位参数 可以有默认值
void func2(int a , int = 1)
{

}


void test02()
{
	func2(10);

}

四、函数重载

  1. C++中 函数名称可以重复
  2. 函数名称相同 又在同一个作用域下
  3. 函数的参数 个数不同 或者 类型不同 或者 顺序不同
void func()
{
	cout << "无参数的func" << endl;
}

void func(int a )
{
	cout << "有参数的func(int a)" << endl;
}

void func(double  a)
{
	cout << "有参数的func(double a)" << endl;
}

void func(double  a , int b)
{
	cout << "有参数的func(double a ,int b)" << endl;
}

void func(int a, double b)
{
	cout << "有参数的func(int a ,double b)" << endl;
}

void test01()
{
	//func(1.1,3);
	func(1, 3.14);
}
  1. 返回值可以作为函数重载的条件吗??? 不可以
void func(int a, double b) //有返回值
{
	cout << "有参数的func(int a ,double b)" << endl;
}

int func(int a, double b)//无返回值
{
	cout << "有参数的func(int a ,double b)" << endl;
	return 1;
}
  1. 当函数重载 碰到了 默认参数时候,要注意避免二义性问题
oid func2(int a,int b = 10)
{

}
void func2(int a)
{

}

void test02()
{
	//func2(10);

}
  1. 引用的重载
void func3(int &a) //引用必须要引合法的内存空间
{
	cout << " int &a" << endl;
}

void func3(const int &a)  //const也是可以作为重载的条件  int tmp = 10; const int &a = tmp;
{
	cout << "const int &a" << endl;
}

void test03()
{
	//int a = 10;
	func3(10);
}
  1. extern C 浅析
  • C++调用C语言函数
//C++中想调用C语言方法

//extern "C" void show(); //show方法 按照C语言方式做连接
//解决的问题就是 在C++中调用C语言的函数

int main(){

	show(); //在C++中 函数是可以发生重载的,编译器会把这个函数名称偷偷改变  _showv  void

	system("pause");
	return EXIT_SUCCESS;
}
  • 另一种方法
#ifdef __cplusplus //两个_下划线
extern "C" {
#endif // !__cplusplus



#include <stdio.h>

	void show();
	
	

#ifdef __cplusplus //两个_下划线
}
#endif // !__cplusplus

五、类的封装

1. C语言下的封装

C语言封装 属性和行为分开处理了 ,类型检测不够

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Person
{
	char mName[64];

	int mAge;

};

void PersonEat(struct Person *p)
{
	printf("%s 在吃人饭 \n",p->mName);
}

void test01()
{
	struct Person p1;
	strcpy(p1.mName, "德玛西亚");

	PersonEat(&p1);
}


struct Dog
{
	char mName[64];

	int mAge;
};

void DogEat(struct Dog * dog)
{
	printf("%s 在吃狗粮 \n", dog->mName);
}

void test02()
{
	struct Dog d;
	strcpy(d.mName, "旺财");

	DogEat(&d);

	struct Person p1;
	strcpy(p1.mName, "老王");

	DogEat(&p1);

}
//C语言封装 属性和行为分开处理了 ,类型检测不够


int main(){
	//test01();

	test02(); //输出  老王 在吃狗粮
	system("pause");
	return EXIT_SUCCESS;
}

2.C++语言下的封装

  1. C++中的封装 严格类型转换检测, 让属性和行为 绑定到一起
    1. 属性和行为作为一个整体来表示生活中的事物
    2. 控制权限 public 公有权限 protected 保护权限 private 私有权限
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

struct Person
{
	char mName[64];

	int mAge;

	void PersonEat()
	{
		cout <<  mName <<"吃人饭" << endl;
	}

};

struct Dog
{
	char mName[64];

	int mAge;

	void DogEat()
	{
		cout << mName << "吃狗粮" << endl;
	}

};

//C++中的封装 严格类型转换检测, 让属性和行为 绑定到一起
// 1 属性和行为作为一个整体来表示生活中的事物
// 2 控制权限 public 公有权限   protected 保护权限  private 私有权限
void test01()
{
	Person p1;
	strcpy(p1.mName, "老王");
	p1.PersonEat();
	//p1.DogEat();
}
  1. struct 和class是一个意思,唯一的不同 默认权限不同
    • struct默认权限是public
    • class默认权限是private
  2. public 类内 类外 都可以访问
    protected 类内可以访问 类外 不可以访问 (子类可以访问)
    private 类内可以访问 类外 不可以访问 (子类不可以访问)
class Animal
{
private:
	//如果我不声明权限,默认的权限是 private
	void eat(){ mAge = 100; };

	int mAge;

public:
	int mHeight;

protected: //保护权限 类内部可以访问 ,(当前类的子类可以访问) , 类外部不可以访问

	int mWeight;

	void setWeight(){ mWeight = 100; };
};

//所谓私有权限 就是私有成员(属性、函数) 在类内部可以访问,类外部不可以方法
//公共权限 ,在类内部和类外部都可以访问
void test02()
{
	Animal an;
	//an.eat();
	//an.mAge; //私有不可以访问到

	an.mHeight = 100; //公有权限在类外部可以访问到
	//an.mWeight = 100; //保护权限 在类外不可访问到
}
  1. 建议将所有成员属性设置为私有
    • 自己提供公共的对外接口来进行set或者get方法访问
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <string>
using namespace std;

class Person
{

public:

	//设置年龄
	void setAge(int age)
	{
		if (age < 0 || age > 100)
		{
			cout << "你这个老妖精" << endl;
			return;
		}
		m_Age = age;
	}
	//获取年龄 读权限
	int getAge()
	{
		return m_Age;
	}

	//读姓名
	string getName()
	{
		return m_Name;
	}
	//写姓名
	void setName(string name)
	{
		m_Name = name;
	}

	//只写的情人
	void setLover(string lover)
	{
		m_lover = lover;
	}

private: //类外不可访问,类内可以访问

	int m_Age  = 0; //年龄 读写
	string m_Name; //公有权限  读写
	string m_lover; //情人  只写

};

void test01()
{
	Person p1;
	p1.setName("老王");

	cout << "p1的姓名:" << p1.getName() << endl;

	//年龄
	p1.setAge(120);

	cout << "p1的年龄:" << p1.getAge() << endl;

	//情人 只能设置 外部我不告诉你
	p1.setLover("仓井");
    
}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值