C++笔记



【1】2021.01.01

作用域

::双冒号作用域运算符
全局作用域,直接加::

记得以前老师说过可以把::看作‘的’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;
int atk = 200;
void test1() {
int atk = 100;
cout << "atk=" << ::atk << endl;
}
int main() {
test1();
cout << "hello " << endl;
return 0;
}

输出为全局作用域下中的atk

atk=200


namespace

namespace主要解决命名冲突问题

  1. 命名空间下可以放函数、变量、结构体、类。
  2. 命名空间必须定义在全局作用域下。
  3. 命名空间可以嵌套命名空间(禁止套娃!)
  4. 命名空间是开放的,可以随时向原来的命名空间添加内容
  5. 匿名/无名命名空间(类似于static,其成员函数只能在当前文件使用)
  6. 命名空间可以起别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include "game1.h"
#include "game2.h"

//namespace主要解决命名冲突问题

//1.命名空间下可以放函数、变量、结构体、类
namespace A {
void func();
int a=20;
struct person
{

};
class animal {};
namespace B {
int a = 10;
}
}
void test02() {
cout << "作用域B下的A:" << A::B::a << endl;
}

//2.命名空间必须定义在全局作用域下
//3.命名空间可以嵌套命名空间
//4.命名空间是开放的,可以随时向原来的命名空间添加内容
namespace A {//此A命名空间会和上面的A命名空间进行合并
int b = 100;
}
void test03() {
cout << "A::下的A为:" << A::a << "B为:" << A::b << endl;
}

//5.匿名/无名命名空间
namespace {
int c = 0;
int d = 0;
}

//当写了无名命名空间相当于写了static int c ,static int d ,静态变量
//只能在当前文件内使用
//6.命名空间可以取别名

namespace verylongname {
int a = 123;
}
void test04() {
//起别名
namespace vln= verylongname;
cout << vln::a << endl;
}

int main() {
test04();
kg::goAtk();
system("pause");
return 0;
}

using声名和using编译指令

1.using 声名

编译器就近原则和using会导致二义性
要避免二义性问题

1
2
3
4
5
6
7
8
9
10
11
namespace KG{
int swk = 10;

}
void test01() {
int swk = 20;
//using KG::swk;
//加上这个声名会出现多次声名error,也就是二义性
cout << "swk=" << swk << endl;
}

2.using 编译指令

1
using namespace xxxx;

与局部变量重名时,则会覆盖命名空间中的同名成员,而不会报错(避免了二义性)
但是如果同时using了多个namespace,也会出现二义性!

1
2
3
4
5
6
7
8
9
10
11
12
namespace LOL {
int swk = 30;
}
void test02() {
//int swk = 20;
//using 编译指令
using namespace KG;//打开房间,避免二义性
cout << "swk=" << swk << endl;
using namespace LOL;
//如果打开多个房间,也要避免二义性
cout << "swk=" << LOL::swk << endl;
}

C++对C语言的加强

1.全局变量检测

C语言中以下全局作用域下的代码不会报错

1
2
int a;
int a = 10;

C++中以上代码就会报错,int a重定义

2.函数检测

包括参数类型检测、返回值检测、函数调用参数检测
以下代码可以在C中运行,最多警告,而C++中,这里有四三处错误

1
2
3
4
5
6
int getS( w, h) {//(1).参数类型
//return w * h; (2).无返回值
}
void test02() {
getS(10, 10,10);//(3).函数调用错误
}

3.类型转换

在C语言中,void相当于万能指针,任何指针都可以直接等于void
但是在C++中,必须强制转换

1
2
3
4
void test03() {
char* p = (char *)malloc(sizeof(64));//malloc返回void*
//void *必须强转
}

4.struct增强/优化

在C语言中的结构体不可以增加函数,并且创建结构体必须加上struct关键字
C++中的结构体可以加函数,并且创建新的时候可以不加struct关键字

1
2
3
4
5
6
7
8
9
10
11
struct person {
int age;
void plusage() { age++; };//C++的struct中可以加函数
};
void test04() {
person p1;
//C++使用的时候可以不加struct关键字
p1.age = 1;
p1.plusage();//调用结构体中的函数
cout << p1.age << endl;
}

5.bool类型

C语言中没有bool类型
bool只有true和flase两个值,0为false,非0为true

1
2
3
4
5
6
7
8
bool flag = true;//只有真或假,0代表假,非0都是真
void test05() {
cout << sizeof(bool) << endl;

flag = 100;
//bool类型非0的值转为1,0就转为0
cout << flag << endl;
}

6.三目运算符

在C语言中三目运算符返回的是值
C++中三目运算符返回值是变量

1
2
3
4
5
6
7
8
void test06() {
int a = 10;
int b = 20;
cout<<"ret="<<( a < b ? a : b)<<endl;
(a < b ? a : b )= 100;//返回b=100;
//C语言返回的是值,C++中返回的是变量
cout << "a=" << a << " b=" << b << endl;
}

7.const

地址修改

在C语言中的const可以通过地址修改
C++中的const是存在符号表中,无法通过地址修改

C++中:

1
2
3
4
5
6
7
8
9
10
11
const int m_A = 10;//受到保护,不可修改
void test07() {
//m_A = 100;
const int m_B = 20;//C++中是真常量了,可以初始化数组
//m_B = 100;
int* p = (int*)&m_B; //*p指向的是一块临时空间
//相当于是int tmp=m_B;
//int*p=(int *)&tmp;
*p = 200;
printf("*p=%d,b=%d\n", *p, m_B);//这里只是修改了一个临时空间,所以对m_B没有任何影响
}

C语言中:

1
2
3
4
5
6
7
8
9
const int m_A = 10;//受到保护,不可修改
void test07() {
//m_A = 100;
const int m_B = 20;//伪常量,甚至都不可以int arr[m_B],不可初始化数组
//m_B = 100;
int* p = (int *)&m_B;
*p = 200;
printf("*p=%d,b=%d\n",*p ,m_B);
}

(2)链接

C++中const默认是内部链接,需要通过extern来提高作用域
C语言中const是内部链接,不需要extern来提高作用域


【2】2020.01.02

const

1.内存分配情况

众所周知,有内存就可以绕过编译器修改const。

const取地址会分配临时内存
使用extern,编译器也会给const变量分配内存

1
2
3
4
5
void test01()
{
const int A = 10;
int* B = (int*)&A;//分配临时内存
}

2.修改const变量

主要就是通过地址绕过,这样就不会报错,并且可以修改掉const变量

(1)普通变量初始化const变量

1
2
3
4
5
6
7
void test02() {
int a = 10;
const int b = a;
int* p = (int*)&b;
* p = 1000;
cout << "b=" << b;
}

(2)自定义数据类型

目前只用过的自定义数据类型是结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
struct person
{
string name;
int age;
};
void test03() {
const person p1;
//p1.name = "aaa"; 不能直接修改
person* p = (person*)&p1;
p->name = "小蓝";
(*p).age = 18;
cout << "name=" << p1.name << " age=" << p1.age << endl;
}

基础引用

1.语法

引用主要是起别名
Type &别名=原名

1
2
3
4
5
6
void test01() {
int a = 10;
int& b = a;
b = 20;
cout << "a=" << a << " b=" << b << endl;
}

2.必须初始化

引用必须初始化,一旦初始化后就不能修改了

1
2
3
4
5
6
7
8
9
void test02() {
//int &a;//会报错,引用必须初始化!
int a = 10;
int& b = a;//引用初始化后不可以修改!
int c = 20;
//&b = c;//不叫初始化,叫赋值,只能初始化,不能这样赋值
b = c;//赋值
cout << "a=" << a << " b=" << b << " c=" << c << endl;
}

3.对数组建立

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void test03() {
int arr[10];
for (int i = 0; i < 10; i++) {
arr[i] = i;
}
//给数组起别名
//方法1
int(&parr)[10] = arr;
for (int i = 0; i < 10; i++)
cout << parr[i] << endl;
cout << endl;
//方法2
typedef int(ARRAYREF)[10];//一个具有十个元素的int类型的数组
ARRAYREF& parr2 = arr;
for (int i = 0; i < 10; i++)
cout << parr2[i] << endl;
}

参数的传递方式

1.值传递

这种传递有作用域限制,从输出就可以看出,修改的并不是原来的值,而是新的两个值

1
2
3
4
5
6
7
8
9
10
11
12
void myswap(int a,int b) {
int tmp=a;
a = b;
b = tmp;
cout << "myswap::a==" << a << " myswap::b=" << b << endl;
}
void test01() {
int a = 10;
int b = 20;
myswap(a, b);//值传递方式
cout << "a=" << a << " b=" << b << endl;
}

2.地址传递

可以实现修改原值,将地址取出来给指针指向,直接修改地址中的值,实现修改值

1
2
3
4
5
6
7
8
9
10
11
12
13
void myswap2(int*a,int*b) {
int tmp = *a;
*a = *b;
*b = tmp;

cout << "myswap::a==" << *a << " myswap::b=" << *b << endl;
}
void test02() {
int a = 10;
int b = 20;
myswap2(&a, &b);//值传递方式
cout << "a=" << a << " b=" << b << endl;
}

3.引用传递

引用就是起别名,我们用引用相当于给原值取个别名,然后修改的别名其实也就是原值

1
2
3
4
5
6
7
8
9
10
11
12
13
void myswap3(int &a ,int&b) {//&a=a,用别名的方式
int tmp = a;
a = b;
b = tmp;
cout << "myswap::a==" << a << " myswap::b=" << b << endl;

}
void test03() {
int a = 10;
int b = 20;
myswap3(a,b);//值传递方式
cout << "a=" << a << " b=" << b << endl;
}

4.注意事项

  1. 引用必须引一个合法的内存空间(常量不是合法空间,但是后面会有常量引用)
  2. 不要返回一个局部变量的引用(局部变量加上static可以解决这个问题)
1
2
3
4
5
6
7
8
9
10
11
12
int& dowork() {
int a = 10;
return a;
}
void test04() {
//int& a = 10;//必须合法内存空间!
int &res=dowork();//vs处理方式不同
cout << res << endl;//第一次是编译器做了优化,后续就是乱码了
cout << res << endl;
cout << res << endl;
cout << res << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
int& dowork2() {
static int a = 10;
return a;
}
void test05() {
int& res = dowork2();//如果函数的返回值为引用,那么这个函数的调用可以做为左值
dowork2() = 1000;//a=1000;
cout << res << endl;//第一次是编译器做了优化,后续就是乱码了
cout << res << endl;
cout << res << endl;
cout << res << endl;
}

指针的引用

1.指针的指针

第一段是我个人理解,不知道怎么表述,就是一段代码

1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;
int main() {
int a = 10;
int* p1= &a;
int** p2 = &p1;
cout << **p2 << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct person
{
int age;
};

void alloc(person **p) {//**p具体的person对象 *p对象的指针 p指针的指针
*p = (person*)malloc(sizeof(person));
(*p)->age = 100;
}
void test01() {
person* p = NULL;
alloc(&p);
cout << p->age << endl;
}

2.利用指针来开辟空间

就是把p取了个别名叫p,后面要使用p时就直接用别名p,看起来乱七八焦,其实代码一看就悟了!
用一级的指针引用 可以代替二级指针

1
2
3
4
5
6
7
8
9
void alloc2(person*& p) {//指针的引用
p = (person *)malloc(sizeof(person));
p->age = 10000;
}
void test02() {
person* p = NULL;
alloc2(p);
cout << p->age << endl;
}

常量引用

终于到这一步了,前面不是说过常量不是合法的内存空间,所以无法引用吗:

1
int& a = 10;//必须合法内存空间!

这里我们用一个方法(加Const)绕过编译器(经典绕过!!),并且这次是加了Const内部操作是编译器自己把自己绕过

1
2
3
const int& ref = 10;//加入const后编译器处理方式为
//int tmp=10;
//const int& ref = tmp;

然后就是经典修改const了

1
2
3
int* p = (int*)&ref;
*p = 1000;
cout << "ref=" << ref << endl;

(只是说明const可以被修改,不是让你真的写个const然后又去修改哈,那样多少有点问题了)

常量引用场景:修饰形参

1
2
3
4
5
6
7
8
9
void showva(const int &val) {
//val += 1000;//如果只是想显示内容而不是修改内容,那么就用const修饰这个内容
//其实加了const还是能修改,只是修饰,代表让我们不要动这个值,防君子不防小人
cout << "val="<<val << endl;
}
void test02() {
int a = 10;
showva(a);
}

以上就是说明const int& a=10;会分配内存!所以才能实现赋值哦~


【3】2021.01.06

又来了莫名其妙的工作,耽误惹两天,555

设计圆类求周长

主要为了了解类怎么写

设计类/抽象类语法:

1
2
3
4
5
class 类名{
public:
设置 成员属性
设置 方法/成员函数
};

宏定义咱尽量用const

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const double pi = 3.14;
//1.设计一个类,求圆周长
//周长公式:2*pi*r
class Circle {//class代表声名一个类 后面紧跟的是类的名称
public://公共权限
//求圆的周长
//在类里面写的函数叫 成员函数
double getzc() {
return 2*pi*R;
}
//设置半径的成员方法
void setr(int r) {
R = r;
}
//半径: 成员属性
int R;
};
void test01() {
//通过类来创建一个圆
Circle c1; //圆 (对象)
//c1.R = 10;//(给这个对象的半径来赋值)
//通过成员函数简介给圆设置半径
c1.setr(10);
cout << c1.getzc() << endl;
}

设计学生类

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

创建一个学生的过程叫实例化(通过类来创建对象的过程叫实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class student {
public:
//设置姓名
void setname(string getname) {
name = getname;
}
//设置学号
void setid(int getid) {
id = getid;
}
void show() {
cout << "name= " << name << " id=" << id << endl;
}
string name;
int id;
};
void test01() {
//创建一个学生(创建一个学生这个过程叫实例化)
//通过类来创建对象的过程 叫实例化
student st;
st.setname("zhangsan");
st.setid(1);
// cout << "st姓名为:" << st.name << " id=" << st.id << endl;
st.show();
}

使用类,创建对象=实例化对象
类名 对象名
通过对象来设置属性或调用成员函数

类和对象关系?
类是对对象的抽象
对象是类的实例


内联函数的引出-宏函数的缺陷

1.宏的缺陷

宏函数(define)无作用域,无类型。

1
2
3
4
5
6
7
//定义一个加法
#define Myadd(x,y) ((x)+(y))
void test01() {
int ret = Myadd(10,20)*20;
//预期600 10+20*20 所以要加小括号
cout << "ret=" << ret << endl;
}

上面的加法看似没有问题,但如果我们的宏是三目,传入值是++a,输出值就会有问题了

1
2
3
4
5
6
7
#define mycompare(a,b) ((a)<(b))?(a):(b)
void test02() {
int a = 10;
int b = 20;
int ret=mycompare(++a, b); //((++a)<(b))?(++a):(b) 预期11,实际出来12
cout << "ret=" << ret << endl;
}

但是如果用普通函数就没有问题

1
2
3
4
void mycp(int a,int b) {
int ret = a < b ? a : b;
cout << "ret:::" << ret << endl;
}

把这个普通函数变成内联函数

1
2
3
4
inline void mycp(int a,int b) {
int ret = a < b ? a : b;
cout << "ret:::" << ret << endl;
}

内联几乎与宏一样,只是避免了一些不是函数而导致的缺陷,目的就是来代替宏的。


2.注意事项

内联函数的声名和实现都要加inline,否则不算内联函数

1
2
inline void fun();//内联函数声名
inline void func() {}//如果函数实现时,没有加上inline关键字,那么这个函数依然不算内联函数

3.空间换时间

空间好理解,时间就是如果是函数会有出入栈开销。如果直接运行代码就会省去出入栈的开销,而内联其实就是替换,所以没有出入栈


4.类内部的内联函数

类内部的成员函数,编译器会默认加inline关键字。


5.内联函数和编译器

inline只是给编译器的建议,编译器不一定会接受。有时候就算你没给建议编译器也会自动加上(比如类内部),一个好的编译器将会内联小的、简单的函数。

以下情况编译器不会考虑将函数进行内联编译:

  1. 存在任何形式的循环语句。
  2. 过多条件判断语句。
  3. 函数体过于庞大。
  4. 对函数进行取址操作。

【4】2021.01.09-10

函数的默认参数以及占位参数


1.默认参数

C语言没默认参数和占位参数

函数的默认参数,参数后面=…
注意事项:

  1. 如果一个位置有了默认参数,那么从这个位置开始,从左向右都必须有默认参数。
  2. 传入参数,如果有参数,就用传入的参数,没有就用默认值。
  3. 如果函数声名里面有默认参数,那么函数实现时必须没有!就是说,函数声名和函数实现只能其中一个有默认参数。(否则会报错)
    1
    2
    3
    void myfunc(int a = 10, int b = 10);
    void myfunc(int a,int b) {
    }
  4. 以下情况:
    1
    2
    3
    4
    5
    6
    void func(int a ,int b=10 , int c=10) {
    cout << "a+b+c=" << a + b +c<< endl;
    }
    void test01() {
    func(1,2);//必须严格参数匹配,否则不止默认参数的时候,编译器不知道你给的两个值是给谁
    }

2.占位参数

如果有了占位参数,函数调用的时候必须提供这个参数
ps.占位参数没有什么大用处,后面重载++符号才有一点用。

占位参数可以有默认值

1
void func2(int a ,int =1) {}

函数重载

C++中函数名称可以重复。
C语言没有函数重载。


1.实现原理

原理其实是编译器会修饰函数名,但是每个编译器修饰效果不一样。
比如有些void func()和void func(int a)编译器会修饰为_func和_func_int


2.基本语法和注意事项

注意事项:

  1. 必须在同一个作用域下,函数名称相同。
  2. 函数的参数个数不同或者类型不同或者顺序不同。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void func() {
    cout << "无参数func" << endl;
    }
    void func(int a) {
    cout << "1" << endl;
    }
    void func(double a) {
    cout << "2" << endl;
    }
    void func(int a,double b) {
    cout << "3" << endl;
    }
    void func(double a, int b) {
    }
  3. 返回值不可以作为函数重载的条件。(联想cout,cout不像printf可以指定类型,所以返回值的话,cout不会知道到底是哪个返回值。)
  4. 函数重载碰到了默认参数的时候,要注意避免二义性
    1
    2
    3
    4
    5
    6
    7
    void func2(int a,int b=10) {
    }
    void func2(int a) {
    }
    void test02() {
    //func2(10);
    }

3.引用的重载

前置知识:引用必须引用合法内存空间
(const也可以作为重载条件,想想那个编译器自己绕过自己的原理)

1
2
3
4
5
6
7
8
9
10
11
12
13
void func3(int &a) {//引用必须要引合法内存空间
cout << "int& a "<< endl;
}
void func3(const int &a) {//const也是可以作为重载条件
//int tmp=10;
//const int &a=tmp;
//经典temp值绕过
cout << "const int &a" << endl;
}
void test03() {
//func3(10);引用必须要引合法内存空间
func3(10);//当func3加了const就不会报错了
}

extern C浅析

当C++想调用C语言的方法,extern解决了C++文件中调用C语言的代码。

设test.c为:

1
2
3
4
5
#pragma once
#include "test.h"
void show() {
printf("hello world!\n");
}

直接在.CPP中使用#include "test.h"
那么test.h中必须是:

1
2
3
4
5
6
7
8
9
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
void show();
#ifdef __cplusplus
}
#endif

如果.cpp中使用了extern "C" void show();

show方法按照C语言方式做链接,不再按照C++方法

test.h可以直接:

1
2
#include <stdio.h>
void show();

为什么会这样呢?明明test.h中有show方法啊,怎么还需要这样操作呢?

因为!上面不是讲了重载吗,重载原理就是C++编译器修改了函数的名称,所以才能实现重载,我们这里找show方法的时候,C++其实将函数名修改了,所以用C语言方式连接时,找不到show方法。
所以有两种方法,让C语言代码通过C++方式链接了。


C语言和C++下的封装

一拉一踩,饭圈行为!

1.C语言的封装

在C++对C语言的加强中,有写到关于结构体的区别,实际上,就是C中struct中不能加函数

1
2
3
4
5
6
struct person
{
char name[64];
int age;
//void fun();//C的结构体不能加函数
};

就是由于不能在struct中添加函数,只能在全局写函数,而全局的函数,任何一个struct都能调用,而且C中函数的话,有缺陷——类型检测不够。所以会混乱。
比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void personeat(struct person *p) {

printf("%s 在吃饭\n",p->name);
}
void test01() {
struct person p1;
strcpy(p1.name,"小明");
personeat(&p1);
}

struct dog
{
char name[10];
int age;
};
void dogeat(struct dog*dog1) {
printf("%s 在吃狗粮\n", dog1->name);
}
void test02() {
struct dog dog1;
strcpy(dog1.name,"旺财");
dogeat(&dog1);

struct person p1;
strcpy(p1.name,"老王");
dogeat(&p1);//由于类型检测不够,导致老王吃狗粮了
}

2.C++的封装

C++语言中的封装:将属性和行为作为一个整体来表示生活中具体的事物。有访问权限。
class和struct唯一区别就是默认权限不同。class默认为private,struct默认public

struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的。

  1. 严格的类型转换检测
  2. 属性和行为绑定到一起
    属性和行为作为一个整体来表示生活中的事物。
  3. 控制权限

public(公共权限):在类内部和类外部都可以访问。
protected(保护权限):类内可以访问,子类可以访问,但是类外不可以访问。
private(私有权限):所谓的私有权限就是私有成员,在类内部可以访问,子类和类外部都不可以访问。

成员包括:属性,函数(也叫方法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
struct person
{
char name[64];
int age;
void personeat() {
cout << name << " 吃饭" << endl;
}
//void fun();//C的结构体不能加函数
};
struct dog
{
char name[10];
int age;
void dogeat() {
cout << name << " 吃狗粮" << endl;
}
};
void test01() {
person p1;
strcpy(p1.name,"老王");
p1.personeat();
//p1.dogeat();
//会报错,dogeat不是person的成员
}
//struct 和class是一个意思,唯一不同:默认权限
//struct是public 但是class默认权限是private
class animal {
//如果不声名权限,默认权限是private
void eat() { age = 100; };
int age;
public:
int height;
protected://保护权限,类内部可以访问,当前类的子类可以访问,类外部不可以访问
int weight;
void setwei() { weight = 100; }
};
void test02() {
animal an;
//an.eat();//是私有权限!不可以访问,调用不了
an.height = 100;//共有权限在类外部可以访问
//an.weight = 100;//保护权限,类外部不可以访问
}
int main() {
test02();
system("pause");
return EXIT_SUCCESS;
}

建议成员变量都设置为私有

其实就相当于调用接口,调用public的接口来得到private的成员变量。

放一段代码就懂了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class person {
public://其实相当于接口,调用接口来得到private
void setage(int getage) {//写权限
age = getage;
}
int getage() {//读权限
return age;
}
string getname() {//读权限
return name;
}
void setname(string name1) {
name=name1;
}
void setlover(string lover1) {
lover = lover1;
}
private:
int age=0;//只读
string name;
string lover;
};
void test01() {
person p1;
cout << p1.getage() << endl ;
}

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

【5】2021.01.11

面向对象设计案例-立方体案例

灰常简单的入门基础代码,前面两章都提到过
需要注意的就是const的使用

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class cube {
public:
void getabc(int geta,int getb,int getc) {
a = geta;
b = getb;
c = getc;
}
void gets() {
cout << "这个立方体面积为:" << (2 * a * b + 2 * a * c + 2 * b * c) << endl;
//return (2 * a * b + 2 * a * c + 2 * b * c);
}
void getv() {
cout << "这个立方体体积为:" << (a * b * c) << endl;;
}
int geta1() const{
return a;
}

//通过成员函数来判断是否相等
bool cpr(cube &c2) {
if(a==c2.a)
return true;
else
{
return false;
}
}
private:
int a;
int b;
int c;
};
bool isSama(const cube &c1,cube &c2) {//引用没有开销!所以尽量用引用
//虽然因为不修改,加const更严谨,但是这里要调用成员方法,而成员方法可以修改private值,所以这里不能用const,(但如果成员属性改成public就可以加上const之后去调用属性了)
//但是如果成员函数也加上const来表明不可修改,这里就可以加上const了,比如这个c1。
if (c1.geta1() == c2.geta1()) {
return true;
}
else
{
return false;
}
}
void test01() {
cube cube1;
int x, y, z;
cin >> x >> y >> z;
cube1.getabc(x, y, z);
cube1.gets();
cube1.getv();

//通过全局函数判断俩立方体是否相等
cube c2;
int x2, y2, z2;
cin >> x2 >> y2 >> z2;
c2.getabc(x2,y2,z2);
bool res = isSama(cube1,c2);
if (res)cout << "a相同" << endl;
else cout << "a不同" << endl;
cout << endl;
//通过成员函数来判断
bool res2 = cube1.cpr(c2);
cout << "res2=" <<res2<< endl;
}
int main() {
test01();
system("pause");
return EXIT_SUCCESS;
}

面向对象设计案例-点和圆的关系

  • 设计一个圆形类,和一个点类,计算点和圆的关系。
  • 假如圆心坐标为x0,y0,半径为r,点的坐标为x1,y1。

这波就很有内味儿了。把声名和实现分开写了。(是mvc的那种感觉!!

1.声名

头文件里面写声名,只写声名不写过程!

circle.h:(头文件,用来声名)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
#include <iostream>
#include "point.h"
using namespace std;
class circle {
public:
void setr(int ther);
int getr();
//设置圆心
void setC(point p);
//获取圆心
point getC();
//利用成员函数来判断
void isin(point& pp);
private:
int r;
point center;
};

point.h:(还是用来声名的,不写过程!)

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
#include <iostream>
using namespace std;
class point {//点类
public:
void setx(int thex);
void sety(int they);
int getx();
int gety();
private:
int x;
int y;
};

2.实现

下面我们来实现circle和point

circle.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include "circle.h"
using namespace std;

void circle::setr(int ther) {
r = ther;
}
int circle::getr() {
return r;
}

//设置圆心
void circle::setC(point p) {
center = p;
}
//获取圆心
point circle::getC() {
return center;
}

//利用成员函数来判断
void circle::isin(point& pp) {
int dis = (center.getx() - pp.getx()) * (center.getx() - pp.getx())
+ (center.gety() - pp.gety()) * (center.gety() - pp.gety());
int disr = r * r;
if (dis == disr) {
cout << "成员函数:点在圆上" << endl;
}
else if (disr > dis)cout << "成员函数:点在圆上" << endl;
else
{
cout << "成员函数:点在圆外" << endl;
}
}

point.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "point.h"
void point::setx(int thex) {
x = thex;
}
void point::sety(int they) {
y = they;
}
int point::getx() {
return x;
}
int point::gety() {
return y;
}

注意要加上::作用域运算符。

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include "circle.h"
#include "point.h"
using namespace std;
//利用全局函数来判断点和圆的关系
void inc(circle &c,point &p) {
//圆心和点的距离
int dis = (c.getC().getx()-p.getx())* (c.getC().getx()-p.getx())+ (c.getC().gety() -p.gety())*(c.getC().gety()-p.gety());
int rdis = c.getr() * c.getr();
if (dis == rdis) {
cout << "点在圆上" << endl;
}
else if (rdis > dis)cout<<"点在圆上"<<endl;
else
{
cout << "点在圆外" << endl;
}
}
void test01() {
point p1;
p1.setx(10);
p1.sety(10);
point cp;
cp.setx(10);
cp.sety(0);
circle c1;
c1.setC(cp);
c1.setr(10);

//利用全局
inc(c1,p1);
c1.isin(p1);
}
int main() {
test01();
system("pause");
return EXIT_SUCCESS;
}