c++笔记2

14、c++的对象

对象和结构的区别;

结构:包含各种类型的变量;

对象:包含各种函数、和变量;

设计对象的时候引用class关键字创建类,和结构形状差不多;

将变量称之为属性,函数称之为方法;

14造车,创建类:类的实际应用;

一个awm型号的车;

属性(c变量):车身颜色、油

方法(c函数):改变颜色、加油;

类的声明和定于;

cpp 复制代码
#include <iostream>

class MyClass_che
{
public:
	MyClass_che();
	~MyClass_che();
	std::string yanse;
	void gaibian_yanse(std::string);

	int you;
	void gaibian_you(int);

private:

};
void MyClass_che::gaibian_yanse(std::string  str)// ::表域符 ,指示实在这个类里面的方法/或属性
{
	MyClass_che::yanse = str;
}
void MyClass_che::gaibian_you(int you)
{
	MyClass_che::you = you;
}

类定义时候:不能对常量赋值,除非是加static

awm a;创建了一个对象a属于awm型号的车

以上结合就理解了这就是对象;这个对象有颜色、油属性;有改变颜色、改变油的方法;

作用域 ::表域符 ,指示是在这个类里面的方法/或属性

同类对象可以赋值;

awm a,b;

b=a;

16构造器

构造器和通常方法的主要区别;

-构造器的名字必须和它所在的类的名字一样;

-系统在创建某个类的实例时会第一时间自动调用这个类的构造器;

-构造器永远不会返回任何值

构造器如下

构造器定义如下;相当于一个函数,没有viod,且在声明创建一个对象后被执行;(相当于c里面的 回调函数,创建一个对象就回调)

MyClass_che::MyClass_che()

{

}

每个类至少一个构造器;没写构造器,编译器也会给你定义一个构造器( 内容为空 );

析构器

属性和构造器一样;不过前面加~波浪线

程序结束时调用:该程序使用内存,就在析构器里面释放内存

应用

比如构造器打开文本:打开文本需要内存

,析构器关闭文本 ; 关闭文本就释放了内存

cpp 复制代码
#include <iostream>
#include<fstream>
class MyClass_che
{
public:
	MyClass_che();
	~MyClass_che();
	std::string yanse;
	void gaibian_yanse(std::string);
	std::fstream pf;
	int you;
	void gaibian_you(int);
	

private:

};



MyClass_che::MyClass_che()
{
	pf.open("123.txt", std::ios::in | std::ios::out);
}

MyClass_che::~MyClass_che()
{
	pf.close();
}

17this的继承和类的继承

this指针,表当前方法的所属类;

cpp 复制代码
void MyClass_che::gaibian_you(int you)
{
	MyClass_che::you = you;
	this->you = you;//此时的this等效于MyClass_che,右边的you代表形参,左边代表这个类的属性
}

基类:

子类;

两个类的描述:

基类是公共有的,子类继承基类,并且多于基类的属性和方法;

例如;

动物是基类

{

吃饭、睡觉

}

甲鱼子类、猪是子类

甲鱼

{

基类的属性和方法

独特属于甲鱼的属性:游泳

}

{

基类的属性和方法

独特属于猪的属性:上树

};

cpp 复制代码
#include <iostream>
class dongwu//基类
{
public:
	dongwu();
	~dongwu();
	void eat();

private:

};

void dongwu::eat()//基类方法
{

	std::cout << "我在吃饭" << std::endl;
}
dongwu::dongwu()
{
}

dongwu::~dongwu()
{
}
class pig:public dongwu//pig 继承于(分号)  dongwu 
{
public:
	pig();
	~pig();
	void shangshu();//属于猪的独特属性

private:

};

pig::pig()
{
}

pig::~pig()
{
}
void pig::shangshu()
{
	std::cout << "上树了" << std::endl;
}


int main()
{

	pig pig1;//构建一只猪1对象,类别是子类pig
	pig1.eat();//这是继承的基类的方法
	pig1.shangshu();//这是子类特有的

    std::cout << "Hello World!\n";
}

18子类的构造器和析构

创建对象时:

先执行父类的构造器

才到子类的构造器;

销毁对象时:

子类的最后一条语句结束后调用基类的析构器;

  1. 首先调用子类的析构器。
  2. 然后调用父类的析构器。

带参数的构造器声明

父类,基类

cpp 复制代码
class dongwu
{
public:
	dongwu( std::string N_name);//带参的基类析构函数
	~dongwu();

private:

};

子类

cpp 复制代码
class pig:public dongwu//继承父类的子类
{
public:
	pig(std::string N_name);//带参的子类析构函数
	~pig();

private:

};

构造器定义

带参子类构造器的定义

//子构造器的形式 子构造器 :父类构造器(不带类型 的参数)

cpp 复制代码
dongwu::dongwu(std::string N_name)
{
name = N_name;
}

这个name = N_name;

个人认为是:相当于tihs->name = N_name; 初始化了tihs->name;

然后再继承给子类

cpp 复制代码
pig::pig(std::string N_name):dongwu::dongwu( N_name)//子构造器的形式  子构造器 :父类构造器(不带类型 的参数)
{
}

子类析构器

编译器自动添加;可不用处理;

19访问控制

类的属性和方法有访问控制

访问控制可以在编译的时候编译器可以检查到合法性;

在声明类的时候,访问控制如下关键字

public: 公共 此下的属性和方法 可以被任何代码访问

protected: 保护 此下的属性和方法,可以被这个类本身方法和子类方法访问

1、外部代码无法通过过子类去调用父类的保护
private: 私有 此下的属性和方法,只有这个类本身可以访问

cpp 复制代码
class dongwu
{
public://任何代码都可以访问
	dongwu( std::string N_name);//带参的基类析构函数
	~dongwu();
	std::string  name;
	protected://子类方法内和这个类方法内可以访问
	int a;
private://只能 dongwu temp;由这个类的 temp 访问
	int b;

};

main函数里面无法找到a和b;a被保护 b是私有;

在pig类方法里面,可以引用父类的被保护的a;

cpp 复制代码
pig::pig(std::string N_name):dongwu::dongwu( N_name)//子构造器的形式  子构造器 :父类构造器(不带类型 的参数)
{
	//name = N_name;
	this->a = 0;
}

20覆盖函数和重载

覆盖如下:

子类继承了父类的eat()方法,

子类中又声明且定义了eat()的方法,此时子类调用的eat方法,就会覆盖继承父类的eat();

所以子类调用的时候,调用的方法其实就是子类的eat();

cpp 复制代码
class dongwu
{
public://任何代码都可以访问
	dongwu( std::string N_name);//带参的基类析构函数
	~dongwu();
	std::string  name;
	void eat();
	protected://子类方法内和这个类方法内可以访问
	int a;
private://只能 dongwu temp;由这个类的 temp 访问
	int b;

};


void dongwu::eat()//父类的
{
	std::cout << " eat \n"; 
}
class pig:public dongwu//继承父类的子类
{
public:
	pig(std::string N_name);//带参的子类析构函数
	~pig();
	void eat();

private:

};

void pig::eat()//子类的
{
	std::cout << "吃到了 大蛋糕";
}

重载

通过重载等效覆盖,通过改变子类的参数个数,或者参数类型,就可以保留继承父类的eat()

C++学习笔记-CSDN博客

参考其中的章节: 06:函数的重载

cpp 复制代码
class dongwu
{
public://任何代码都可以访问
	dongwu( std::string N_name);//带参的基类析构函数
	~dongwu();
	std::string  name;
	void eat();
	protected://子类方法内和这个类方法内可以访问
	int a;
private://只能 dongwu temp;由这个类的 temp 访问
	int b;

};


void dongwu::eat()//父类的
{
	std::cout << " eat \n"; 
}
class pig:public dongwu//继承父类的子类
{
public:
	pig(std::string N_name);//带参的子类析构函数
	~pig();
	void eat(int);

private:

};

void pig::eat(int)//子类的
{
    dongwu::eat();//只要前面文本定义了这个 方法就可以直接这样调用
	std::cout << "吃到了 大蛋糕";
}

补充: dongwu::eat();//只要前面文本"定义 "了这个 方法就可以直接这样调用

21友元关系

在aa类声明的时候添加

friend class bb;//指定友元为bb,所以类bb可以访问aa的保护

cpp 复制代码
#include <iostream>
class aa
{
public:
protected:
    int k1;
private:
    friend class bb;//指定友元为bb,所以类bb可以访问aa的保护
};

class bb
{
public:
    void set(class aa* k);
protected:
    int y1;
private:
};

void  bb::set(class aa *  k)//传递aa的类指针
{
    k->k1 = 0;//调用了aa的保护属性,无错误,所以可以调用
}

int main()
{
    
    std::cout << "Hello World!\n";
}

22、静态属性和静态方法

静态成员

1、需要在外部定义和初始化

2、只需要在类里面声明;

3、静态成员先于类,不是独特地属于任何类;

静态成员是所有同类对象共享的,再静态方法里面不能访问普通成员;

普通方法可以访问静态成员和方法;

this指针

1、this指针每个类自动生成的私有成员

2、当一个对象被生成的时候,该对象的this指针就指向了对象的首地址

3、任何方法都可以用this指针,这个this指针是隐藏传送到方法里面的;get()其实是get(类指针* this );方法被调用指针就传入;

4、this可以指向每个成员和方法

结论:所以静态方法不属于任何对象,所以无法确定为对象地址,所以无法使用this指针;

调用方法坚持使用 类::方法;可以提高代码阅读性

如cat::get();

静态成员共享例子

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;
class dongwu
{
public:
	dongwu(std::string N_name);
	~dongwu();
	static int get_cout();
	int get();
	std::string name;

private:
	static int cout;
	int a;

};
int dongwu::cout = 0;
int dongwu::get_cout()
{
//	a++; 会编译错误
	return cout;
}
int dongwu::get()
{

	return cout;
}
dongwu::dongwu(std::string N_name)
{
	name = N_name;
	cout++;
	std::cout << name<<cout;
}

dongwu::~dongwu()
{
	cout--;
}
class cat:public dongwu
{
public:
	cat(std::string N_name);
};
cat::cat(std::string N_name):dongwu::dongwu(N_name)
{
}

int main()
{
	cat a1("小猫");
	cat a2("小猫");
	std::cout << '\n' << a1.get()<<'\n';
	{
		cat a3("小猫");
		cat a4("小猫");
		std::cout << '\n' << a1.get_cout() << '\n';
	}
	std::cout << '\n' << a1.get_cout() << '\n';
}

24虚方法;

虚方法关键字 在类的声明里面的方法添加关键字virtual

cpp 复制代码
class dongwu
{
public:
	dongwu(std::string N_name);
	~dongwu();
	std::string name;
	virtual void play();///虚方法
private:
	static int cout;

};

应用场景:

//指针是基类,创建的内存是子类;导致调用子类方法不能覆盖,必须用虚方法解决

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;
class dongwu
{
public:
	dongwu(std::string N_name);
	~dongwu();
	std::string name;
	virtual void play();///虚方法
private:
	static int cout;

};
dongwu::dongwu(std::string N_name)
{
	name = N_name;
}
void dongwu::play()
{
	std::cout << "动物在玩";
}


dongwu::~dongwu()
{
}
class cat:public dongwu
{
public:
	cat(std::string N_name);
	void play();

};
cat::cat(std::string N_name) :dongwu(N_name)
{

}
void cat::play()//子类方法
{
	std::string str=this->name;
	str.append("这只猫再玩毛线");
    std::cout << str;
}

int main()
{
	dongwu* p = new cat("小花");//指针是基类,创建的内存是子类;导致调用子类方法不能覆盖,必须用虚方法解决
	p->play();//如果基类不加virtual 虚方法关键字 ,方法是基类方法,子类没有成功覆盖

}

补充:

new 创建内存

delete 删除内存

new cat ;创建了一个子类内存

delete :释放了一个子类的内存

25、纯虚方法

纯虚方法:

在虚方法后面=0;

作用,优化代码,告诉编译器,不需要寻找执行实现,这是一个纯虚方法,任何都可以覆盖,也可以说不用可以去覆盖了,每个继承的都可以无顾虑的实现覆盖;

多态性:

一个名字,可以执行不同的操作;

编译时的多态:通过重载实现,编译时运行快

运行时的多态:通过虚函数实现,运行时灵活和抽象

析构函数就是虚方法;

是为了当基类指针删除子类对象时,正确调用子类析构函数;

思路(仅仅为了理解):相当于为了覆盖子类方法,用虚方法,使得调用方法时是执行子类方法,而不是基类的方法;

特别说明:基类被继承后,基类的析构才是虚函数;

26、运算符重载

以下5个运算符不允许重载

.(成员访问运算符)

**.***成员指针访问运算符(本人认为 ->)

::域运算符

sizeof( ) (尺寸运算符)

?: (条件运算符)

运算符重载形式:

函数类型 operator 运算符(参数列表);

Complex operator +(Complex&d);//重载运算符 相当于返回值类型为Complex类

当 Complex类 遇到加号 且后面为同类Complex,运算符执行如下(函数运算)

例子如下备注,仅个人理解

cpp 复制代码
#include <iostream>
class Complex
{
public:
	Complex();
	~Complex();
	 Complex(double r, double i);
	 Complex operator +(Complex&d);//重载运算符 相当于返回值类型为Complex类   当  Complex类 遇到加号 且后面为同类Complex,运算符执行如下运算
	 void print();

private:
	double real;
	double imag;
};

Complex::Complex()
{
}

Complex::~Complex()
{
}

Complex::Complex(double r, double i)//重载函数
{
	real = r;
	imag = i;
}
Complex Complex::operator +(Complex& d)//括号里面的是类对象,传入对象  运算符重载
{
	Complex c;
	c.imag = imag + d.imag;
	c.real = real + d.real;
	return c;
}

void Complex::print()
{
	std::cout << "(" << real << "," << imag << "i)";
}

int main()
{
	Complex c1(1.0, 2.0), c2(3.0, -4.0), c3;
	c3 = c1 + c2;//该对象是Complex类遇到+,发生了重载,使用指定的运算
	int a, b=8, c=9;
	a = b + c;
	c3.print();

    std::cout << "Hello World!\n"<<a;
}

小鱼理解:

c1+c2

c1.operator+(c2);编译器理解为,相当于调用一个函数得到返回值

运算符重载作为类友元函数

运算符重载

cpp 复制代码
Complex operator +(Complex &a, Complex &b)//在类中被声明了友元,所以可以访问私有;这同时是个运算符重载
{
	return Complex(a.real + b.real, a.imag + b.imag);//
}

在类里面声明为友元

cpp 复制代码
class Complex
{
public:
	Complex();
	~Complex();
	 Complex(double r, double i);
	// Complex operator +(Complex&d);//重载运算符 相当于返回值类型为Complex类   当  Complex类 遇到加号 且后面为同类Complex,运算符执行如下运算
	 friend Complex operator +(Complex& a, Complex& b);//声明为该类的友元函数
	 void print();

private:
	double real;
	double imag;
};

例子

cpp 复制代码
#include <iostream>
class Complex
{
public:
	Complex();
	~Complex();
	 Complex(double r, double i);
	// Complex operator +(Complex&d);//重载运算符 相当于返回值类型为Complex类   当  Complex类 遇到加号 且后面为同类Complex,运算符执行如下运算
	 friend Complex operator +(Complex& a, Complex& b);//声明为该类的友元函数
	 void print();

private:
	double real;
	double imag;
};

Complex::Complex()
{
}

Complex::~Complex()
{
}
Complex::Complex(double r, double i)
{
	real = r;
	imag = i;
}
Complex operator +(Complex &a, Complex &b)//在类中被声明了友元,所以可以访问私有;这同时是个运算符重载
{
	return Complex(a.real + b.real, a.imag + b.imag);//
}


void Complex::print()
{
	std::cout << "(" << real << "," << imag << "i)";
}

int main()
{
	Complex c1(1.0, 2.0), c2(3.0, -4.0), c3;
	c3 = c1 + c2;//该对象是Complex类遇到+,发生了重载,使用指定的运算
	int a, b=8, c=9;
	a = b + c;
	c3.print();

    std::cout << "Hello World!\n"<<a;
}

28再次重载<< (对数据流)

原理和26差不多,且用得不多;

29、多继承

当一个对象有多个身份的时候,就有了多种关系

一个人既可以是学生也可以是老师;基类是人,子类是老师、学生;还有一个子类既是学生也是老师;

因为多继承:所以可以访问不同父类的保护成员;

多继承的类声明

class 子类: public 父类, public 父类 //(class 子类:分号 public 父类, 逗号public 父类)

多继承的析构器

子类::子类析构(std::string N_name) : 分号 父类析构( N_name), 逗号 父类析构(N_name)

{

}

N_name为参数;

cpp 复制代码
techer_student::techer_student(std::string N_name):techter( N_name), student(N_name)
{
}

例子

cpp 复制代码
#include <iostream>
#include<string>
//*********************************************************************
class peson
{
public:
	peson(std::string N_name);

protected:
	std::string name;
private:

};

peson::peson(std::string N_name)
{
}
//*******************************************************************************
class techter:public peson
{
public:
	techter(std::string N_name);
protected:
	std::string tech_banji="我作为老师,教大学三年级";

private:


};

techter::techter(std::string N_name):peson(N_name)
{
}
//**********************************************************************************
class student:public peson
{
public:
	student(std::string N_name);
protected:
	std::string student_banji="我作为学生,在读清华博士";

private:

};

student::student(std::string N_name):peson(N_name)
{
}
//******************************************************
class techer_student: public techter, public student
{
public:
	techer_student(std::string N_name);
	void jieshao();
protected:
	std::string techer_student_banji="我是学生也是老师";
private:

};

techer_student::techer_student(std::string N_name):techter( N_name), student(N_name)
{
}

void techer_student::jieshao()
{
	std::cout << student::student_banji << '\n' << techter::tech_banji << '\n' << techer_student::techer_student_banji << '\n';
    //多继承 既可以使用student 的保护  也可以使用techter的保护
}


int main()
{ 
	techer_student lin("彭冠霖");
	
	lin.jieshao();
    std::cout << "Hello World!\n";
}

30、虚继承

虚继承的作用

‌**虚继承的主要作用是解决多重继承中的"菱形继承"问题** ‌。在多重继承中,当一个类继承了多个父类,而这些父类又继承了同一个基类时,会导致子类中存在多份基类的拷贝,这会造成对基类成员的访问存在多义性

cpp 复制代码
void techer_student::jieshao()
{
	std::cout << student::student_banji << '\n' << techter::tech_banji << '\n' << techer_student::techer_student_banji << '\n';
	techer_student::stud() ;//调用了名字
	techer_student::tech();调用了名字  本来就是同一个人,只能用同一个名字,在继承过来后应该统一名字
    //多继承 既可以使用student 的保护  也可以使用techter的保护
}
对基类成员的访问存在多义性

造成了继承了多个名字;

如下程序;

cpp 复制代码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<string>
//*********************************************************************
class peson
{
public:
	peson(std::string N_name);

protected:
	std::string name;
private:

};

peson::peson(std::string N_name)
{
}
//*******************************************************************************
class techter:public peson
{
public:
	techter(std::string N_name);
protected:
	std::string tech_banji="我作为老师,教大学三年级";
	void tech();
private:


};

techter::techter(std::string N_name):peson(N_name)
{
	name = N_name;
}
void techter::tech()
{
	std::cout << "我是" << name;
}
//**********************************************************************************
class student:public peson
{
public:
	student(std::string N_name);
protected:
	std::string student_banji="我作为学生,在读清华博士";
	void stud();
private:

};

student::student(std::string N_name):peson(N_name)
{
	name = N_name;
}
void student::stud()
{
	std::cout << "我是" << this->name;
}
//******************************************************
class techer_student: public techter, public student
{
public:
	techer_student(std::string N_name1, std::string N_name2);
	void jieshao();
protected:
	std::string techer_student_banji="我是学生也是老师";
private:

};

techer_student::techer_student(std::string N_name1,std::string N_name2):techter( N_name1), student(N_name2)
{
}

void techer_student::jieshao()
{
	std::cout << student::student_banji << '\n' << techter::tech_banji << '\n' << techer_student::techer_student_banji << '\n';
	techer_student::stud() ;//调用了名字
	techer_student::tech();调用了名字  本来就是同一个人,只能用同一个名字,在继承过来后应该统一名字
    //多继承 既可以使用student 的保护  也可以使用techter的保护
}


int main()
{ 
	techer_student lin("彭冠霖","小彭");
	
	lin.jieshao();
	
    std::cout << "Hello World!\n";
}

虚继承,在每个继承的时候,在前面添加virtual

在子类的构造器添加基类继承 和父类

使用虚继承后的程序:和以上程序相比,没啥体现差别,除了关键字;

cpp 复制代码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<string>
//*********************************************************************
class peson
{
public:
	peson(std::string N_name);

protected:
	std::string name;
private:

};

peson::peson(std::string N_name)
{
}
//*******************************************************************************
  class techter: virtual public peson
{
public:
	techter(std::string N_name);
protected:
	std::string tech_banji="我作为老师,教大学三年级";
	void tech();
private:


};

techter::techter(std::string N_name):peson(N_name)
{
	name = N_name;
}
void techter::tech()
{
	std::cout << "我是" << name;
}
//**********************************************************************************
class student: virtual public peson
{
public:
	student(std::string N_name);
protected:
	std::string student_banji="我作为学生,在读清华博士";
	void stud();
private:

};

student::student(std::string N_name):peson(N_name)
{
	name = N_name;
}
void student::stud()
{
	std::cout << "我是" << this->name;
}
//******************************************************
class techer_student:virtual public techter, virtual public student
{
public:
	techer_student(std::string name);
	void jieshao();
protected:
	std::string techer_student_banji="我是学生也是老师";
private:

};

techer_student::techer_student(std::string name):techter(name), student(name),peson(name)
{
}

void techer_student::jieshao()
{
	std::cout << student::student_banji << '\n' << techter::tech_banji << '\n' << techer_student::techer_student_banji << '\n';
	techer_student::stud() ;//调用了名字
	techer_student::tech();调用了名字  本来就是同一个人,只能用同一个名字,在继承过来后应该统一名字
    //多继承 既可以使用student 的保护  也可以使用techter的保护
}


int main()
{ 
	techer_student lin("彭冠霖");
	
	lin.jieshao();
	
    std::cout << "Hello World!\n";
}

再对比如下,效果一样;所以没体现出虚继承的差别;很疑惑

cpp 复制代码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<string>
//*********************************************************************
class peson
{
public:
	peson(std::string N_name);

protected:
	std::string name;
private:

};

peson::peson(std::string N_name)
{
}
//*******************************************************************************
  class techter:  public peson
{
public:
	techter(std::string N_name);
protected:
	std::string tech_banji="我作为老师,教大学三年级";
	void tech();
private:


};

techter::techter(std::string N_name):peson(N_name)
{
	name = N_name;
}
void techter::tech()
{
	std::cout << "我是" << name;
}
//**********************************************************************************
class student:  public peson
{
public:
	student(std::string N_name);
protected:
	std::string student_banji="我作为学生,在读清华博士";
	void stud();
private:

};

student::student(std::string N_name):peson(N_name)
{
	name = N_name;
}
void student::stud()
{
	std::cout << "我是" << this->name;
}
//******************************************************
class techer_student: public techter,  public student
{
public:
	techer_student(std::string name);
	void jieshao();
protected:
	std::string techer_student_banji="我是学生也是老师";
private:

};

techer_student::techer_student(std::string name):techter(name), student(name)//,peson(name)
{
}

void techer_student::jieshao()
{
	std::cout << student::student_banji << '\n' << techter::tech_banji << '\n' << techer_student::techer_student_banji << '\n';
	techer_student::stud() ;//调用了名字
	techer_student::tech();调用了名字  本来就是同一个人,只能用同一个名字,在继承过来后应该统一名字
    //多继承 既可以使用student 的保护  也可以使用techter的保护
}


int main()
{ 
	techer_student lin("彭冠霖");
	
	lin.jieshao();
	
    std::cout << "Hello World!\n";
}

31、32错误处理和调试

错误分为编译错误和运行错误

编译时错误

经验:

  1. 在编程的时候保持一种风格、一旦决定要如何命名变量和函数、如何缩进、何种格式编写代码;
  2. 认真对待编译器的错误和警告
  3. 先画流程图
  4. 编译错误、先完整的看一遍代码、再矫正错误;
  5. 注意基本语法
  6. 把可能有问题的代码注释掉
  7. 换一个环境或者开发工具:可能是杀毒软件,什么之类的影响;
  8. 头文件包含
  9. 留意变量的作用域和命名空间
  10. 休息一下:效率下降后需要休息;
  11. 多使用调试工具
  12. 把调试好的程序控制保存起来;把代码划分成模块,来搭建新程序可以减少很多时间;

运行时的错误

逻辑漏洞;bug同一个产品一个好一个坏;时有时无没法确定;

经验;

  1. 保持一种良好的编程风格
  2. 多注释,注释好,特别是参数变化;简单代码,不要啰嗦
  3. 操作符优先级,括号很保险
  4. 输入输出合法性检查
  5. 不要做任何假设:用户不会按照你的想法去使用你的程序;
  6. 划分单元模块,这样测试方便

让函数返回错误代码

输入输出错误码

使用climits头文件

给定操作系统上的取值范围:每种数据的上下限给我们使用

如:SHORT_MAX 、SHORT_MIN分别代表短整类型的最大取值和最小取值;

例子:使用使用climits头文件

cpp 复制代码
#include <iostream>
#include<climits>//引用c限制头文件
class ftory
{
public:
	ftory(unsigned short num);
	~ftory();
	unsigned long get_ftory();
	bool inRange();

private:
	unsigned short number;
};

ftory::ftory(unsigned short num)
{
	this->number = num;
	std::cout << "输入参数为" << this->number<<'\n';
}

ftory::~ftory()
{
}
unsigned long ftory::get_ftory()
{
	unsigned long sun = 1;
	for (int i=1;i<= number;i++)
	{
		sun *= i;
	}
	return sun;
}
bool ftory::inRange()
{
	unsigned long temp= ftory::get_ftory();
	if (temp >= USHRT_MAX )//这是climit头文件里面的限制参数
		return  false; //超出限制就返回false
	else
		return true;
}


int main()
{
	ftory a(20);
	 std::cout<< a.get_ftory()<<'\n';
	 std::cout << a.inRange() << '\n';
    std::cout << "Hello World!\n";
}

33、运行错误、异常捕获

#include<cassert>//前面的c表示时c库里面的

assert(条件判断);条件不成立时,提示错误,可以用这个函数定位运行错误

输出窗口可以定位文件和行数

cpp 复制代码
#include <iostream>
#include<cassert>

int main()
{
    uint16_t i;
    std::cin >> i;
    assert(i<100);
    std::cout << "Hello World!\n";
}
#include

捕获异常

运行错误分为两种

  1. 开发 调试 测试过程中,尽可能的查找和定位错误;使用函数assert等等;
  2. 和最终用户有关,尽可能的把用户感受放第一位;用户不懂技术,要用户能轻松使用;输出也不能全部开放,看不懂只会增加用户麻烦;

大公司微软都不可能没有bug,关键在于后续升级

捕获异常:

为了对付潜在的编程错误。异常:就是与期望不相符合的反常现象

捕获异常的的基本使用思路

  1. 安排c++代码去尝试某件事 (try 语句)
  2. 如果发生问题就抛出一个异常
  3. 再安排一些代码捕获这个异常并进行相应的处理(catch语句)

Try 至少配一条 catch语句,否则中止程序

Catch (int a) {.........}//捕获int型

Catch (bool) {.........}//捕boolt型

Catch (char) {.........}

//Catch 可以捕获任何类型的

C++ 中Exception 的文件 声明exception 的基类。可以用这个基类来做私人的子类作为异常管理

可以抛出和捕获exception 类或者子类的对象:以值传递抛出,以引用方式捕获;

在抛出异常的方法添加throw (抛出异常类型指针)

bool ftory::inRange()throw (const char *)

{

}

try{

可以抛出异常的方法调用

}

catch (抛出的异常类型)//对应异常的catch (指定为 const char* 类型)

{

std::cout << e;//输出异常

}

例子

#include<exception>//异常头文件 没体现出来

cpp 复制代码
#include <iostream>
#include<climits>//引用c限制头文件
class ftory
{
public:
	ftory(unsigned short num);
	~ftory();
	unsigned long get_ftory();
	bool inRange();

private:
	unsigned short number;
};

ftory::ftory(unsigned short num)
{
	this->number = num;
	std::cout << "输入参数为" << this->number << '\n';
}

ftory::~ftory()
{
}
unsigned long ftory::get_ftory()
{
	unsigned long sun = 1;
	for (int i = 1; i <= number; i++)
	{
		sun *= i;
	}
	return sun;
}
bool ftory::inRange()throw (const char *)//能抛出异常的方法定义
{
	unsigned long temp = ftory::get_ftory();
	if (temp >= USHRT_MAX)
	{//这是climit头文件里面的限制参数
		throw "数值太大了 抛出了一个字符异常 ";//抛出异常 为const char *类型
		return  false; //超出限制就返回false
	}
	else
	{
		
		return true;

	}
}


int main()
{
	ftory a(20);

	std::cout << a.get_ftory() << '\n';

	try {//可能会抛出异常额函数
		std::cout << a.inRange() << '\n';
	}
	catch (const char* e)//对应异常的catch (指定为 const char* 类型)
	{
		std::cout << e;
	}
	std::cout << "Hello World!\n";
}

34动态内存管理

静态内存,结构体、变量、数组 静态内存,固定占用固定大小的内存

动态内存:由一些没有名字、只有地址的内存块构成,那些内存块是在程序运行期间动态分配;

由new 申请内存返回地址;

1、如inte *p =new int;申请了int类型大小的内存,并且返回内存起始地址

2、没有足够的内存空间,new语句抛出异常std::bad_alloc异常;

3、用完内存之后要用delete释放内存;且将指针设置为null;没有释放就是bug;

4、new 出来的内存要先使用填充数据,再访问读取;或者构造器里面直接先初始化

关于这个p=null 使用这个p无法访问,否则访问就程序中止;

cpp 复制代码
int *p  =new int;

delete p;

p=null;

35动态数组

cpp 复制代码
	int a = 10;
	int* p = new int[a];//建立动态数组

	delete []p;//删除数组

delete []p;//删除数组 方括号+数组的指针

相关推荐
Cathy Bryant8 分钟前
矩阵乘以向量?向量乘以向量?
笔记·神经网络·考研·机器学习·数学建模
递归不收敛1 小时前
Conda 常用命令汇总(新手入门笔记)
笔记·conda
前端橙一陈2 小时前
Salesforce Developer Edition(开发者版) 搭建测试环境
经验分享·笔记·其他
电子小子洋酱2 小时前
BearPi小熊派 鸿蒙入门开发笔记(4)
笔记·华为·harmonyos
摇滚侠3 小时前
Spring Boot 3零基础教程,WEB 开发 通过配置类代码方式修改静态资源配置 笔记32
java·spring boot·笔记
聪明的笨猪猪4 小时前
Java JVM “内存(1)”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
_dindong5 小时前
Linux网络编程:Socket编程TCP
linux·服务器·网络·笔记·学习·tcp/ip
摇滚侠5 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 属性优先级 行内写法 变量选择 笔记42
java·spring boot·笔记
摇滚侠6 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 总结 热部署 常用配置 笔记44
java·spring boot·笔记
rechol6 小时前
汇编与底层编程笔记
汇编·arm开发·笔记