C++Day2
设计一个类求圆的周长
#include <iostream>
using namespace std;
const double PI=3.14;
class Circle
{
public://公共权限
//求圆周长
//类中的函数 称为成员函数/成员方法
//所有的成员函数都必须在类内声明,但可在类外定义
double calculateZC();
{
return 2*PI*m_R;
}
//半径
//类中的变量 称为成员变量/成员属性
int m_R;
};
void test01()
{
Circle c1;//c1代表一个圆 通过类创建一个对象 实例化对象
//给c1半径赋值
c1.m_R=10;
//求c1周长
cout<<"圆的周长为:"<<c1.calculateZC()<<endl;
}
- 类的基本思想
- 数据抽象
- 封装
- class+类名{成员变量 成员函数};
- 公共权限
- 设计成员属性
- 半径 int m_R;
- 设计成员函数
- 获取圆周长 int calculatZC(){}
- 通过类创建对象的过程称为实例化对象
宏缺陷
-
必须加括号保证运算完整
-
#define MYADD(x,y) x+y void test01() { int a=10; int b=20; int ret=MYADD(a,b)*20; cout<<ret<<endl;//输出不为600 } //改为 #define MYADD01(x,y) ((x)+(y)) void test02() { int a=10; int b=20; int ret=MYADD01(a,b)*20; cout<<ret<<endl; }
-
-
即使加了括号,有些运算依旧与预期不符
-
#define M(a,b) (((a)<(b))?(a):(b)) void test02() { int a=10; int b=20; int ret=M(++a,b);//预期为11 结果为12 (((++a)<(b))?(++a):(b)) cout<<"ret="<<ret<<endl; }
-
内联函数
-
在C++中,预定义宏是由内联函数实现的。内联函数本身也是一个函数,具有普通函数的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,不需要函数调用的开销(调用前要保存在寄存器,并在返回时恢复;可能需要拷贝实参;程序转向一个新的位置继续执行)
-
在普通函数(非成员函数)函数前面加上inline使之成为内联函数,但是必须注意必须函数体与声明结合在一起,否则编译器会将它作为普通函数对待
-
//内联函数 //函数的声明和实现必须同时加关键字inline才算内联函数 inline void func() inline void func() { } //类内部的内联函数在类内部定义的函数自动成为内联函数,在函数前都隐式加了inline
-
以下情况编译器可能不会将函数进行内联翻译
- 存在任何形式的循环语句
- 存在过多的条件判断语句
- 函数体过大
- 对函数进行取址操作
-
对于小的简单的函数编译器可能会将其内联
constexpr函数
- 函数的返回类型与所有形参类型都为字面值类型
- 函数体中必须有且只有一条return语句
- 通常将内联函数与constexpr函数放在头文件中
函数默认参数与占位参数
//默认参数 形参中:类型 变量=默认值
//如果有一个位置有了默认参数,那么从这个位置从左到右都必须有默认值
int func(int a=10,int b=10)
{
return a+b;
}
void test01()
{
cout<<func()<<endl;//20
cout<<func(20)<<endl;//20+10=30
}
//函数的声明和实现只能有一个提供默认参数
//void A1(int a=10,int b=20);
//void A1(int a=10,int b=20){}
//占位参数 只写一个类型进行占位,调用时必须要传入占位值
void func(int a,int)
{
}
void test()
{
func(10,1);
}
命名的强制类型转换
- 形式:cast-name(expression);
- type是转换的目标类型
- expression是要转换的值
- cast-name
- static_cast
- 任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast
- dynamic_cast
- const_cast
- 只能改变运算对象的底层const
- reinterpret_cast
- 为运算对象的位模式提供较低层次上的重新解释
- static_cast
函数重载
//函数重载条件
//1.在同一个作用域,在不同作用域下可以函数名与形参均相同
//2.函数名称相同
//3.参数个数、类型、顺序不同
//4.返回值不可以作为函数重载条件
//main函数不能重载
void fun()
{
}
void fun(int a)
{
}
void myFunc(int &a)
{
cout<<"myFunc(int &a)调用"<<endl;
}
void myFunc(const int &a)
{
cout<<"myFunc(const int &a)调用"<<endl;
}
void test()
{
int a=10;
myFunc(a);//调用第一个,a为可读可写
myFunc(10);//调用第二个,第一个为int &a=10不合法,const int &a=10合法
}
//当函数重载遇到默认参数,避免二义性出现
void func(int a,int b=10)
{
}
void func(int a)
{
}
void test()
{
func(10);//不知道调用哪一个
}
//如果在内层作用域中声明名字,将隐藏外层作用域中声明的同名实体。在不同的作用域中无法重载函数名。在C++中,名字查找发生在类型检查之前
externC浅析
-
在C++中有函数重载会修饰函数名,会导致链接失败
-
extern "C" void show();//告诉编译器在别的文件寻找show(),用C语言的方式做链接
-
//或者在.h文件中 #ifdef _cplusplus extern "C" { #endif #include <stdio.h> void show(); #ifdef _cplusplus } #endif //将{}中内容用C语言的方式做链接
类和对象
类的封装
//C++封装理念:将属性与行为作为一个整体
//将属性与行为加以权限控制
struct Person
{
char name[64];
int age;
void PersonEat()
{
cout<<name<<"在吃饭"<<endl;
}
};
struct Dog
{
char name[64];
int age;
void DogEat()
{
cout<<name<<"在狗粮"<<endl;
}
};
- class默认权限为私有权限,struct默认权限为公共权限
- 访问权限
- public公共权限
- 成员在类内类外都可以访问
- private私有权限
- 成员在类内可以访问,在类外不可以
- 儿子不可以访问父亲的private权限
- protected保护权限
- 成员在类内可以访问,在类外不可以
- 儿子可以访问父亲的protected权限
- public公共权限
将成员变量设置为私有
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;
}
private:
string m_Name;//姓名 可读可写
int m_Age;//年龄 只读
string m_Lover;//情人 只写
};
void test01()
{
Person p;
//p.m_Name="张三";
//可以将char*隐式类型转换为string
p.setName("张三");
cout<<"姓名:"<<p.getName()<<endl;
}