目录
一、两个小练习
设计一个类,求圆的周长
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
const double PI = 3.14;
// C = 2 * PI * m_R
class circular {
public: //公共权限
//类中的函数 称为 成员函数或者成员方法
//求圆周长
double GetCircumference()
{
return 2 * PI * m_R;
}
//设置半径
void SetRadius(int r)
{
m_R = r;
}
// 获取半径
int GetRadius()
{
return m_R;
}
//类中的变量 称为成员变量或成员属性
//半径
int m_R;
};
void test01()
{
circular c1; //通过类 创建一个对象 实例化对象
//c1.m_R = 10; //直接设置半径
c1.SetRadius(10);
cout << "圆的半径:" << c1.GetRadius() << endl;
cout << "圆的周长:" << c1.GetCircumference() << endl;
}
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
设计一个学生类案例
class student {
public:
//姓名
string m_Name;
//学号
int m_Id;
//设置姓名
void SetName(string name)
{
m_Name = name;
};
//设置学号
void SetId(int Id)
{
m_Id = Id;
};
//显示学生信息
void ShowStudent()
{
cout << " 姓名 : " << m_Name << " 学号 : " << m_Id << endl;
};
};
void test02()
{
student s1;
s1.SetName("wzh");
s1.SetId(1);
s1.ShowStudent();
student s2;
s2.SetName("ls");
s2.SetId(2);
s2.ShowStudent();
student s3;
s3.SetName("zs");
s3.SetId(3);
s3.ShowStudent();
}
二、宏缺陷
c++出现之后,使用预处理宏会出现两个问题:
第一个在c中也会出现,宏看起来像一个函数调用,但是会有隐藏一些难以发现的错误。
第二个问题是c++特有的,预处理器不允许访问类的成员,也就是说预处理器宏不能用作类类的成员函数。
2.1、宏缺陷1:必须加括号保持运算完整
#define MYADD(x,y) ((x) + (y))
void test01()
{
int a = 10;
int b = 20;
int ret = MYADD(a, b) * 20;
cout << "ret = " << ret << endl;
}
2.2、宏缺陷2:即使加了括号,也可能出现和预期不符的问题
//宏缺陷2 : 即使加了括号,也可能出现和预期不符的问题
#define MYCOMPARE(x,y) (((x)<(y)) ? (x):(y))
//普通函数 不会出现和预期结果不同的结果
void Compare(int x, int y)
{
int ret = x < y ? x : y;
cout << "ret = " << ret << endl;
}
void test02()
{
int a = 10;
int b = 20;
//int ret = MYCOMPARE(++a, b); //预期结果是11,实际结果是12,(((++x)<(y)) ? (++x):(y))
//cout << "ret = " << ret << endl;
Compare(++a, b); //结果是11
}
为了保持预处理宏的效率又增加安全性,而且还能像一般成员函数那样可以在类里访问自如,c++引入了内联函数(inline function).
三、内联函数
内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,可以进行参数,返回值类型的安全检查,又可以作为成员函数。
以下情况编译器可能考虑不会将函数进行内联编译:
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
/* 内联函数
* 函数的声明和实现必须同时加关键字 inline 才算内联函数
* 内联函数的好处 : 解决宏缺陷,本身是一个函数,带来宏优势,以空间换时间,在适当的时候展开
*/
inline void func();
inline void func() {};
//类内部的成员函数 在函数前都隐式的加了关键字 inline
四、函数的默认参数和占位参数
4.1、函数的默认参数
//默认参数 语法 形参 类型 变量 = 默认值
//注意事项:如果有一个位置有了默认值,那么从这个位置起,从左到右都必须有默认值
int func(int a, int b = 10, int c = 10)
{
return a + b + c;
}
void test01()
{
cout << func(20) << endl;
}
默认参数的注意事项
/* 函数声明
* 函数实现
* 函数的声明和实现,只能有一个提供默认值,不可以同时加默认值
*/
void myfun(int a, int b);
void myfun(int a = 20, int b = 20) {};
4.2、占位参数
//占位参数,只写一个类型进行占位,在函数调用的时候必须要传入占位值
//占位参数用途,目前没用
void func2(int a, int)
{
}
void test02()
{
func2(10, 1);
}
五、函数重载
5.1、函数重载基本语法
同一个作用域,参数个数不同,参数类型不同,参数顺序不同
//函数重载的条件
//1、在同一个作用域
//2、函数名称相同
//3、参数个数、类型、顺序不同
class Person {
public:
void func()
{
cout << "Person.func() " << endl;
};
};
void func()
{
cout << "func() " << endl;
}
void func(int a)
{
cout << "func(int 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;
}
5.2、函数重载注意事项
返回值不可以作为函数重载的条件
//返回值不可以作为函数重载的条件
//int func(int a, double b)
//{
// cout << "func(int a,double b) " << endl;
//}
5.3、函数重载中 引用两个版本
//函数重载中 引用两个版本
//void func02(int a)
//{
// cout << "func(int a) " << endl;
//}
//避免二义性出现
void func02(int& a)
{
cout << "func(int &a) " << endl;
}
void func02(const int& a)
{
cout << "func(const int &a) " << endl;
}
void test02()
{
int a = 10;
func02(a);
}
5.4、函数重载碰到默认参数 避免二义性出现
//函数重载碰到默认参数 避免二义性出现
void func03(int a, int b = 10)
{
cout << "func03(int a, int b = 10) " << endl;
}
void func03(int a)
{
cout << "func03(int a) " << endl;
}
void test03()
{
//func03(10); //出现二义性
func03(10, 20);
}
六、externC浅析
在c++中包含test.h头文件,直接调用test.c文件中函数,编译器报错
void test02()
{
show(); //_Z4showv; 在c++中有函数重载会修饰函数名,但是show是c语言函数,因此链接失败
}
解决办法:用
extern "C" void show();
代替#include "test.h"
但是往往test.h中有不止这么一个函数,那我们每一个函数都要这样吗?
显然不是的,还是在.cpp中用头文件,只需要在test.h头文件中添加这样的代码:
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
void show();
#ifdef __cplusplus
}
#endif
七、C语言和C++的封装
7.1、c语言的封装
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Person {
char name[10];
int age;
};
void PersonEat(struct Person* p)
{
printf("%s在吃人饭\n", p->name);
}
void test01()
{
struct Person p;
strcpy(p.name, "张三");
p.age = 20;
PersonEat(&p);
}
struct Dog {
char name[10];
int age;
};
void DogEat(struct Dog* p)
{
printf("%s在吃狗粮\n", p->name);
}
void test02()
{
struct Dog d;
strcpy(d.name, "旺财");
DogEat(&d);
struct Person P;
strcpy(P.name, "李四");
DogEat(&P);
}
int main()
{
//test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
编译器会报指针类型不兼容,但是还是可以运行,在c语言中,属性和行为分离
7.2、c++下的封装
class和struct的区别
class的默认权限是公共权限 struct的默认权限是私有权限
权限
public 公共权限 成员 类内 类外 都可以访问
private 私有权限 成员 类内 可以访问 类外 不可访问 儿子不可以访问父亲的private权限
protected 保护权限 成员 类内 可以访问 类外 不可访问 儿子可以访问父亲的protect权限
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
struct Person {
char name[10];
int age;
void PersonEat()
{
printf("%s在吃人饭\n", name);
};
};
struct Dog {
char name[10];
int age;
void DogEat()
{
printf("%s在吃狗粮\n", name);
};
};
//c++封装理念 将行为和属性作为一个整体 来表示生活中的事物
//第二层理念 将行为和属性加以权限控制
void test01()
{
Person p;
strcpy(p.name, "李四");
p.PersonEat();
Dog d;
strcpy(d.name, "旺财");
d.DogEat();
}
//class和struct的区别
//class的默认权限是公共权限 struct的默认权限是私有权限
//权限
//public 公共权限 成员 类内 类外 都可以访问
//private 私有权限 成员 类内 可以访问 类外 不可访问 儿子不可以访问父亲的private权限
//protected 保护权限 成员 类内 可以访问 类外 不可访问 儿子可以访问父亲的protect权限
class Person2 {
public:
string m_Name;
protected:
string m_Car;
private:
string m_Pwd;
public:
void func1()
{
m_Name = "张三"; //公共权限
m_Car = "五菱"; //保护权限
m_Pwd = 123456; //私有权限
}
};
void test02()
{
Person2 p;
p.m_Name = "李四"; //公共权限 类外可以访问
//p.m_Car = "法拉利"; //保护权限 类外不可以访问
//p.m_Pwd = 123; //私有权限 类外不可以访问
}
int main()
{
//test01();
//test02();
system("pause");
return EXIT_SUCCESS;
}