前言
之前在黑马程序员的零基础课程里系统学习了c++,但是黑马程序员的课程还是太慢了,近四百节课让人很难受 ,基本上前一百节后就已经对C语言了解的差不多了(和c++差不多),两百节之后对c++也基本熟悉了。
总归还是太慢了,其中课程的很多内容都是重复出现的,为了方便我将课程中可以省略的重复步骤省略,将其余内容直接以代码加注释的方式展示出来,在其中还加入了《c++程序设计》机械工业出版社的黑皮书的内容进去作为补充。
c++是非常基础的语言,学习也比较容易,如果减去自己的代码编写时间单纯的看懂就可以的话其实不用一个星期就能基本了解。
但是还是需要多练习,很多程序bug等(有版本不适问题,操作系统不适问题)都在是实操中发现并处理。
简单的学习之后就可以应对csp考试,数据结构等课程了就。
我就是本来用java,考csp前学习回顾一下c++想用c++考。java岗的就业情况也比较饱和,会c++一定是很合算的事。
附上第二部分链接
c++速成(vs)短期学会在vs上使用c++编程(2)-CSDN博客
主要内容
引用
New指针
面向对象编程思想
类和对象
重载
分文件编辑
面向对象编程是c++的特殊之处,这一期主要内容都是c++的特有内容,对之后学习java也有帮助。C++编程核心的思想就是oo(面向对象,也是相对来说更加人性化的一种编程思想,类似于结构体)
代码
XuexiC++3.cpp
#include <iostream>
#include<string>
#include "point.h"
#include "circle.h"
using namespace std;
const double PI = acos(-1.0);
//全局变量
int g_a = 0;
const int c_g_a=0;
int* fuck() {
int an = 10;
return &an;
}
int* fuck2() {
int *p=new int(10);//得到的是地址
return p;
}
int* fuck3() {
//new 返回的是该类型的指针
int* p = new int(9);//该变量是9
return p;
}
void test01() {
int* p = fuck3();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
delete p;
//使用关键字delete
//cout <<*p<< endl;//最后一个内存已经被释放 非法操作
}
void test02() {
int *arrtesst02 = new int[10];//返回地址
for (int i = 1; i < 10; i++)
{
arrtesst02[i] = i + 10;
}
for (int i = 0; i < 10; i++) {
cout << arrtesst02[i] << endl;
}
//释放数组要加[]
delete [] arrtesst02;
}
void newSwap1(int a,int b)
{
int temp;
temp =a;
a = b;
b = temp;
cout << "交换后:" << a << "\t" << b << endl;
}
void newSwap2(int* a, int* b) {
int temp=*a;
*a = *b;
*b = temp;
cout << "交换后:" << *a << "\t" << *b << endl;
}
void newSwap3(int &a,int &b) {
int temp;
temp = a;
a = b;
b = temp;
cout << "交换后:" << a << "\t" << b << endl;
}
int& canLeft() {
static int ding = 50;
return ding;
}
void showValue(const int &val) {
cout << val << endl;
}
//函数形参默认参数
int addThree(int a , int b = 98, int c = 520) {
return a + b + c;
}
//占位参数
//占位参数可以有默认参数
void zhanwei(int a,int=20) {
cout << "this is" << a << endl;
//这个int去哪了
//目前占位参数还用不到,以后能用到 后面的课程
}
//函数重载的满足条件
//同一个作用域
//函数名相同
//函数参数类型不同 个数不同 顺序不同都可以
void zhanwei(int a,int b, int c) {
cout << "重载的" << a <<b<<c<< endl;
}
void zhanwei2(int &a) {
cout << "重载的普通版本" << a << endl;
}
void zhanwei2(const int& a) {
cout << "重载的const版本" << a << endl;
}
//设计一个圆类
// 圆的周长 圆的半径
//
class Circle {
//访问权限
public://公共权限
//属性
// 半径
int r;
// 周长
double zhoucahng()
{
return 2 * PI * r;
}
//行为
};
class student {
public:
//属性
string name;
int id;
//行为
void showStudent() {
cout << "姓名:" << name << "\t学号:" << id << endl;
}
void setName(string thename) {
name = thename;
}
void setId(int theid) {
id = theid;
}
};
class person {
public:
string name;
void showname() {
cout << name << endl;
}
protected:
string car;
private:
string password;
};
class c1 {
string name;
void showname() {
cout << name << endl;
}
};
struct c2 {
string name;
void showname() {
cout << name << endl;
}
};
class People {
public:
void setName(string thename) {
name = thename;
}
string getName() {
cout << name << endl;
return name;
}
int getAge() {
cout << age << endl;
return age;
}
void setAge(int theage) {
if (theage < 0 || theage>150) {
cout << "输入有误" << endl;
}
else {
age = theage;
}
}
void setIdol(string theidol) {
idol = theidol;
}
private:
string name;
int age=18;
string idol;
};
//立方体类
class Cube {
public:
void setH(int h) {
m_h = h;
}
void setX(int h) {
m_x = h;
}
void setY(int h) {
m_y = h;
}
int getH() {
return m_h;
}
int getX() {
return m_x;
}
int getY() {
return m_y;
}
int caculateS() {
return 2 * m_x * m_y + 2 * m_x * m_h + 2 * m_h * m_y;
}
int vulumes() {
return m_x * m_h * m_y;
}
bool isSameWithAnother(Cube &c1) {
if (c1.getH() == getH() && c1.getX() == getX() && c1.getY() == getY()) {
cout << "是相等的" << endl;
return true;
}
else {
cout << "不相等的" << endl;
return false;
}
}
private:
int m_h;
int m_x;
int m_y;
};
bool isSame(Cube& c1, Cube& c2) {
if (c1.getH() == c2.getH() && c1.getX() == c2.getX() && c1.getY() == c2.getY()) {
cout << "是相等的" << endl;
return true;
}
else {
cout << "不相等的" << endl;
return false;
}
}
//是否在圆里面 判断点到圆心的距离
bool isInCiecle1(Circle1 &c,point &p) {
int distance = (( p.getX()-c.getCenter().getX() ) * (p.getX()-c.getCenter().getX() )) + ((p.getY()-c.getCenter().getY()) * (p.getY()-c.getCenter().getY()));
cout << p.getX() << "\t" << c.getCenter().getX() << endl;
cout << p.getY() << "\t" << c.getCenter().getY() << endl;
int rdistance = c.getR() * c.getR();
cout << distance << "\t" << rdistance << endl;
if (distance == rdistance) {
cout << "在圆上" << endl;
}
else if (distance < rdistance) {
cout << "在圆内" << endl;
}
else if (distance > rdistance) {
cout << "在圆外" << endl;
}
return true;
}
int main()
{
//面向对象编程
//内存分区模型
//代码区 (所有代码)
//全局区 (全局变量,静态变量和常量)
//栈区 由编译器自动分配释放 存放函数的参数值,局部变量等
//堆区 程序员分配释放,程序员不释放的话,程序结束 的时候操作系统回收
//四个区的意义 不同的区域存放的数据,赋予不同的生命周期,机遇更多的灵活编程
//代码区 程序运行前分配了 编译后形成了exe可执行程序 没执行前有 代码区 全局区
// 代码区是共享的 共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码就好了
// 代码区是只读的 防止程序意外的修改了它的指令
/*
* 全局区 全局变量 静态变量 常量
* 全局区里还有常量区 包括字符串常量和其他常量
* 数据在程序结束后由操作系统释放
*/
std::cout << "Hello World!\n";
//函数体内的都是局部变量
int a=0;
cout << "局部变量a的地址是:" << (int)&a << endl;
cout << "全局变量g_a的地址是:" << (int)&g_a << endl;//离得很远,不在一个区
static int s_a;
cout << "静态变量s_a的地址是:" << (int)&s_a << endl;//和全局变量近,
//常量
//字符串常量 “hello world”
cout << "字符串常量s_a的地址是:" << (int)&"hello world" << endl;//和全局变量近,但是不完全在一个区(相对两个变量远一点)
//const 修饰
// 全局
cout << "全局常量c_g_a的地址是:" << (int)&c_g_a << endl;//全局常量 和常量更近 和全局不远
// 局部
const int c_l_a = 9;
cout << "全局常量c_l_a的地址是:" << (int)&c_l_a << endl;//局部不在全局区 和局部的更近
//程序运行后
/*
* 栈区 不要返回局部变量的地址,局部变量用完就释放了
* 形参数据就放在栈区
*/
int* p = fuck();
cout << *p << endl;//第一次正确是因为编译器做了保留
cout << *p << endl;//x64输出还是10,但是x86输出不是10
//堆区
/*
*运行期间 程序员自己决定 不释放执行完就会自动释放
*/
int*k = fuck2();
cout << *k << endl;
//int *p里存着 堆区的地址 p指针存在栈区 如果程序员不释放10就一直在,除非程序结束
//new 操作
//对应删除使用delete
test01();
//用new 在堆区开辟一个数组
test02();
//引用 给变量起别名
/*
* int a=10 一块内存
* a 代表这个一段内存
* 先写个数据类型 int &别名=原名;
* 修改别名也会对该段内存有操作
*/
int ayingyong = 60;
int& byingyong = ayingyong;
cout << "原本的是:" << ayingyong << "\t引用的是:" << byingyong << endl;
//引用必须要初始化 一开始就要初始化 给出它是谁的别名 一旦初始化后就不能更改 (永远指向,该段内存)
//引用不能更改 之后用等号的效果就是 赋值效果
//引用做函数参数 代替指针
//同样实现地址传参
//值传递
int b = 13;
a = 14;
newSwap1(14, 13);
cout << "实参未改变" << 14 << "\t" << 13 << endl;
//地址传递newswap
newSwap2(&a, &b);
cout << "实参改变" << a << "\t" << b << endl;
//引用传递
newSwap3(a, b);
cout << "实参继续改变" << a << "\t" << b << endl;
//什么时候用到引用做函数返回值
// 不要返回局部变量的引用 存放在栈区 函数执行完之后就释放了 使用引用返回会 返回错误 第一次编译器会做保留
// 理论上已经释放了 就是非法操作
// ----------------
//函数的调用可以作为左值
// 加static就是静态变量 程序运行结束才会释放 在全局区
int& newNameOfcanLeft = canLeft();
canLeft() = 1314;
cout << canLeft() << endl;
cout << newNameOfcanLeft << endl;
//想当与返回值的内容的别名
// 如果函数的返回值是调用,该函数调用可以作为左值
//
//引用的本质 c++内部实现其实是一个指针常量 指针指向不能修改,指向的值可以修改
//编译器遇到引用就变成解引用 b=20----*b=20 使用者不用在乎那么多 编译器帮助处理
//常量引用 作用主要是修饰形参 防止误操作
int achang = 10;
int& ref = achang;
//后面不能直接跟数据 加const就合法 编译器会修改代码 int temp=10;const int ref=temp;
showValue(achang);
//在函数中修改 形参 实参也会跟着改 //在形参前加入 const就可以确保不会被修改
//形参可以给默认值的
//
cout << addThree(1, 2) << endl;
//这里传的 值级别优先,没有传参的情况下才会使用默认值
//如果这个位置已经有了默认参数,从左到右都必须有默认参数 默认值必须一直延伸到形参的末尾
//如果函数声明有了默认参数 函数实现就不能再有默认参数 只能有一个有默认参数 不然会有二义性
//避免程序出现二义性
//函数占位参数
zhanwei(5,20);
zhanwei(5,20,1314);
//函数重载
//允许函数名相同 提高复用性
// 作用于不同的作用域
// 函数名相同
// 函数参数类型不同或者个数不同
// 不能仅按返回类型区分 返回类型编译器不能判断
//函数重载注意事项
//重载函数碰到函数默认参数
//引用作为函数重载条件
int chongzai = 666;
zhanwei2(chongzai);
//调用的是没有加const的那个
zhanwei2(10);
//调用的是加了const代码 本身有问题,但是有const 编译器就创建零时数据
//有默认值的情况尤其注意重载问题 有默认参数的情况下容易出现可以调用两个函数的二义性
//类和对象 封装,继承,多态
//万事万物都可以成为对象
/*
* 封装 属性和行为作为一个整体,表现生活中的事物
*/
//可以通过圆类 来创建一个圆对象
Circle yuan1;//实例化一个圆
yuan1.r = 10;
cout << "圆的周长为:" << yuan1.zhoucahng() << endl;
//实例化
student s1;
s1.name = "小马";
s1.id = 250;
s1.showStudent();
s1.setName("sunny");
s1.showStudent();
/*
* 类中的属性和行为统称为成员
* 行为 成员函数 成员方法
* 属性 成员属性 成员变量
*/
//封装的 意义2
//访问权限
//三种
//公共权限 public 成员类内可以用 类外也可以
//保护权限 protected 成员类内可以用 类外不可以 儿子可以访问父亲的保护内容,但是不能访问其私有内容
//私有权限 private 成员类内可以用 类外不可以
//实例化
person p1;
p1.name = "xiaoma";
p1.showname();
//其余的访问不到 对象里面访问不到
/*struct 默认是public
* class 默认是 private
*/
c1 cclass;
//cclass.name私有不能访问
c2 cstruct;
cstruct.name = "sunny!";
cstruct.showname();
//将成员属性设为私有 可以自己控制读写权限 对于写权限 可以检测数据的有效性
People peo1;
peo1.setName("zhangsan");
peo1.getName();
peo1.setIdol("xiaoma");
peo1.getAge();
peo1.setAge(180);
peo1.setAge(15);
peo1.getAge();
Cube cu1;
cu1.setH(10);
cu1.setX(10);
cu1.setY(5);
cout << "面积是:" << cu1.caculateS() << endl;
cout << "体积是:" << cu1.vulumes() << endl;
Cube cu2;
cu2.setH(10);
cu2.setX(10);
cu2.setY(10);
cout << "面积是:" << cu1.caculateS() << endl;
cout << "体积是:" << cu1.vulumes() << endl;
bool ret = isSame(cu1, cu2);
if (ret) {
cout << "成功啦" << endl;
}
else
{
cout << "失败了" << endl;
}
cu1.isSameWithAnother(cu2);
//案例2 点在圆的哪里
Circle1 cir1;
cir1.setR(10);
point center;
center.setX(0);
center.setY(0);
cir1.setCenter(center);
point po1;
po1.setX(0);
po1.setY(10);
isInCiecle1(cir1, po1);
//类中可以用另一个类作为成员
//通常把不同类分到不同文件里面
//在头文件写 声明 源文件实现
/*
* 头文件 point.h
* #proagma once
* #include...
*
*/
}
circle.h
#pragma once
#include <iostream>
#include<string>
#include "point.h"
using namespace std;
class Circle1 {
public:
//行为
void setR(int r);
int getR();
void setCenter(point center);
point getCenter();
private:
//属性
point m_center;
int radious;
};
point.cpp
#include <iostream>
#include<string>
#include "point.h"
using namespace std;
int x;
int y;
void point::setX(int thex) {
x = thex;
}
void point::setY(int they) {
y = they;
}
int point::getX() {
return x;
}
int point::getY() {
return y;
}
circle.cpp
#include <iostream>
#include<string>
using namespace std;
#include "circle.h"
void Circle1::setR(int r) {
radious = r;
}
int Circle1::getR() {
return radious;
}
void Circle1::setCenter(point center) {
m_center = center;
}
point Circle1::getCenter() {
return m_center;
}
//属性
point m_center;
int radious;