设计一个类,求圆的周长
-
class +类名 (成员变量,成员函数)
-
权限,公共权限 public: 在public: 下的都是公共的
-
设计成员属性 半径: int m_R
-
设计成员函数
获取圆周长 int calculate2()
获取圆半径 int getR()
设置圆半径 void setR()
5.通过类创建对象过程 称为实例化对象 Circle C1;
示例:圆类,计算圆的周长
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//设计一个类,求圆的周长
const double PI = 3.14;
//class + 类名
//周长的公式 2 * pi * m_R
class Circle
{
public://公共权限
//类中的函数 称为 成员函数 或 成员方法
//求圆周长
double calculate2()
{
return 2 * PI * m_R;
}
//设置半径
void setR(int r)
{
m_R = r;
}
//获取半径
int getR()
{
return m_R;
}
//类中的变量 称为成员变量或成员属性
//半径
int m_R;
};
void test01()
{
Circle c1;//通过类 创建一个对象, 实例化对象
//给c1 半径赋值
c1.m_R = 10;
//求c1圆周长
cout << "圆的周长为:" << c1.calculate2() <<"圆的半径为"<<c1.getR () << endl;
}
示例:学生类,姓名和学号,可以赋值和展示
// 设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生姓名和学号
class Student
{
public:
//设置姓名
void setName(string name)
{
m_Name = name;
}
//设置学号
void setId(int id)
{
m_Id = id;
}
//显示学生信息
void showStudent()
{
cout << "学生的姓名为:" << m_Name << " " << "学号为:" << m_Id << endl;
}
//属性:
//姓名
string m_Name;
//学号
int m_Id;
};
void test02()
{
Student s1;
s1.m_Name = "张三";
s1.m_Id = 10086;
cout << "学生的姓名为:" << s1.m_Name <<" " << "学号为:" << s1.m_Id<<endl;
Student s2;
s2.setName("李四");
s2.setId(10010);
s2.showStudent();
}
内联函数
内联函数的引出
宏的缺陷
- 必须要加括号保证运算完整
- 即使加了括号,有些运算依然与预期不符
内联函数的基本概念
在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真正的函数。内联函数具有普通函数的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用内联函数。
在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。
但是必须注意必须**函数体**和**声明**结合在一起,否则编译器将它作为普通函数来对待。
内联函数的好处
避免了宏函数的缺陷同时可以实现宏函数的功能,以空间换时间。
类内部的成员函数在函数前都隐式的加了 inline 关键字,自动成为内联函数。
C++的内联编译会有一些限制,以下情况编译器可能考虑不会将函数进行内联编译
1. 不能存在任何形式的循环语句
2. 不能存在过多的条件判断语句
3. 函数体不能过于庞大
4. 不能对函数进行取址操作
内联函数仅仅只是给编译器一个建议,编译器不一定会接收这种建议,如果你没有将函数声明为内联函数,编译器也可能会将函数做内联编译,一个好的编译器将会内联小的,简单的函数。
函数的默认参数和占位参数
默认参数,可以给函数的形参添加默认的值
如果有一个位置有了默认参数,那么从这个位置其后面的都要有默认参数
// 默认参数 语法 形参 类型 变量 = 默认值
// 注意事项,如果有一个位置有了默认参数,那么从这个位置起,从左到右都必须有默认值
// 注意事项,函数的声明和实现,只能有一个提供默认参数,不可以同时加默认参数
int func(int a = 10, int b = 10)
{
return a + b;
}
函数的声明和实现,只能有一个提供默认参数,不可以同时加默认参数
占位参数也可以有默认的值 void func(int a,int =1)
// 占位参数,只写一个类型进行占位,调用时候必须要传入占位值
void func2(int a, int)
{
}
函数重载
函数重载的基本语法
C++的语法是可以出现函数名称相同的函数的。
函数重载的条件
- 在同一个作用域
- 函数名称相同
- 参数个数、类型和顺序不同
- 加const和不加const的引用
注意:返回类型不可以作为函数重载的条件
函数重载要避免二义性
如函数重载中引用的两个版本,加const和不加const的引用也可以作为重载条件
函数重载碰到默认参数的情况
示例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//函数重载的条件
//1. 在同一个作用域
//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(int a,double b)
{
cout << "func(int a,double b)调用" << endl;
}
void func(double a, int b)
{
cout << "func(double a, int b)调用" << endl;
}
//函数重载中 引用两个版本
void myFunc(int& a) // int & a =10 ,语法错误
{
cout << "myFunc(int & a)调用" << endl;
}
void myFunc(const int& a) // const int & a =10
{
cout << "myFunc(const int & a)调用" << endl;
}
void test01()
{
int a = 10;
//myFunc(a); 调用 int & a 版本
myFunc(10); //调用 const int & a版本,语法不出错
}
//函数重载碰到默认参数,避免二义性出现
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
externC浅析
在C++中有函数重载,会修饰函数名,但是show()是C语言文件中的函数,因此直接用头文件包含链接失败
解决方法:
-
可以在C++文件中添加
extern"C" void show(); //使用这个语句,相当于告诉编译器用C语言方式去链接 对应的函数
-
可以在C的头文件中添加“上三行”和“最后三行”内容
#ifdef __cplusplus
extern "C" {
#endif
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void show();
#ifdef __cplusplus
}
#endif
C语言和C++的封装
C语言中属性和行为分离
struct Person
{
char name[64];
int age;
};
void PersonEat(struct Person* p)
{
printf("%s在吃人饭\n", p->name);
}
void test01()
{
struct Person p;
strcpy(p.name, "张三");
p.age = 18;
PersonEat(&p);
}
C++封装理念
1. 将属性和行为作为一个整体来表现生活中的事务
struct Person
{
int age;
char name[64];
void PersonEat()
{
printf("%s在吃人饭\n", name);
}
};
struct Dog
{
int age;
char name[64];
void DogEat()
{
printf("%s在吃狗粮\n", name);
}
};
2. 将属性和行为加以权限控制
struct和class的区别,class的默认权限是私有的,struct的默认权限是公共的
访问权限:
public 公共权限 成员在类内类外都可以访问
private 私有权限 成员在类内 可以访问 类外 不可以访问 子类不可以访问父类内容
protected 保护权限 成员在类内可以访问 类外 不可以访问 子类可以访问父类内容
struct Person2
{
public:
string m_name;//公共权限
protected:
string m_car;//保护权限
private:
int pwd;//私有权限
public:
void func()
{
m_name = "张三";
m_car = "拖拉机";
pwd = 12346;
}
};
void test01()
{
Person2 p1;
p1.m_name = "张三"; //公共权限
p1.m_car = "拉斯莱斯"; //报错,保护权限类外访问不到
p1.pwd = 123; //报错,私有权限 类外访问不到
}
尽量将成员的属性设置为私有
- 将成员属性都设置为私有的好处,在于自己可以控制读写权限,提供相应接口。
- 可以对设置的内容进行有效性的验证
示例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <string>
using namespace std;
class Person
{
public: //对外就属性提供相关接口
//设置姓名
void setName(string name)
{
m_Name = name;
}
//获取姓名
string getName()
{
return m_Name;
}
//获取年龄
int getAge()
{
return m_Age;
}
//设置情人
void setLover(string Lover)
{
m_Lover = Lover;
}
//获取资产
void setMony(int mony)
{
if (mony < 0 || mony >500) //验证数据有效性
{
cout << "钱太多了" << endl;
return;
}
m_Mony = mony;
}
int getMony()
{
return m_Mony;
}
private:
string m_Name; //姓名 可读可写
int m_Age = 18; //年龄 只读
string m_Lover; // 情人 只写
int m_Mony; // 资产 可读 可写(0~500之间)
};
void test01()
{
Person p;
//可以将char * 隐式类型转换为 string
p.setName("张三");
cout << p.getName() << endl;
//获取年龄
cout << p.getAge() << endl;
//设置情人
p.setLover("Amy"); //是一个只写权限,外部访问不到
//设置资产
p.setMony(600);
cout << p.getMony() << endl;
}
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}