大二C++期末复习(自用)

一、类

1.定义成员函数

输入年份判断是否是闰年,若是输出年份;若不是,输出NO

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
class TDate{
	private:
		int month;
		int day;
		int year;
	public:
		TDate(int y,int m,int d){
			year = y;
			month = m;
			day = d;
		}
		void IsLeapYear(){
			if((year%400 == 0 )||(year%4==0&&year%100!=0)) {
			this->Print()	;
			}
			else cout<<"No"<<endl;
		}
		void Print(){
			cout<<"Yes"<<endl;
			cout<<year<<"/"<<month<<"/"
			<<day<<endl;
		}
}; 
int main(){
	int y,m,d;
	cin>>y>>m>>d;
	TDate s(y,m,d);
	s.IsLeapYear();
	return 0;
}

2.定义头文件,使用类的接口

成员函数定义看作类的内部,如private的变量定义和public成员函数的声明

c 复制代码
//文件名:tdate。h
//预编译处理器
#ifndef TDATE//if not define TDATE将会定义
#define TDATE//定义TDATE
class TDate{
private:
	int year;
	int month;
	int day;
public:
	void Set(int int int);
	void IsLeapYear();
	void Print();
};
#endif

上述是一个tdate.h的类定义 -> 接口

c 复制代码
//tdate.cpp 实现类---成员函数的定义
#include<iostream>
#include"tdate.h"//文件名名称
using namespace std;
void TDate::Set(int y,int m,int d){
	//....
} 

2.调用成员函数

1)指针

c 复制代码
#include<iostream>
#include"tdate.h"//文件名名称
using namespace std;
void somefuc(TDate *ps){
	ps->IsLeapYear();//调用指针输出判断 
}
int main(){
	TDate s;
	s.Set(1983,2,3);
	somefuc(&s);
}

2) 引用

cpp 复制代码
#include<iostream>
#include"tdate.h"//文件名名称
using namespace std;
void somefuc(TDate &ps){
	ps->IsLeapYear();//调用指针输出判断 
}
int main(){
	TDate s;
	s.Set(1983,2,3);
	somefuc(s);
}

**注意区别指针和引用 大部分情况下是相同 **但指针要给新变量分配空间,而引用直接给原来的地址

3.总结

1.应用1为输入年份,应用2是计算点的直角坐标和极坐标

2.掌握实现类的定义 tdate.h 类的实现 tdate.cpp(成员函数定义)

二、构造函数

1.默认构造函数

cpp 复制代码
class Student{
	private:
	    char name[10];  
}; 
int main(){
	Student s;
}

2.无参构造函数

构造函数可以直接调用print

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Desk{
	private:
		int weight;
		int high;
		int width;
		int length;
	public:
		Desk(){
			weight = 20;
			high = 10;
			width = 90;
			length = 100;
			print();
		}
		void print(){
			cout<<weight<<" "
			<<high<<" "
			<<width<<" "
			<<length<<endl;
		}
};
int main(){
	Desk d;
}

3.传参构造函数

见1.1(常见)

4.重载构造函数

1.重载过程中参数个数不一样才能构造成功

2.在构造无参传递过程中,不用加(),如

Student s( ); ---error 不用加括号

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Student{
	private:
		int grade;
		float gpa;
		int num;
	public:
		Student(){
			grade = 100;
			gpa = 5.0;
			num = 123;
			cout<<grade<<" "<<gpa<<" "<<num<<" "<<endl;
		}
		Student(int s,float g){
			grade = s;
			gpa = g;
			num = 456;
			cout<<grade<<" "<<gpa<<" "<<num<<" "<<endl;
		}
		Student(int s){
			grade = s;
			gpa = 3.6;
			num = 789;
			cout<<grade<<" "<<gpa<<" "<<num<<" "<<endl;
		}
};

int main(){
	Student s1;
	Student s2(90,4.7);
	Student s3(80); 
}

5.嵌套构造函数

main函数开始运行,创建Pair对象p,调用Pair构造函数,为private变量分配空间(int变量,Student,Teacher),最后执行自己的public钟的成员函数,

一步一步的执行

**private 成员变量会在 public 成员函数之前分配空间**

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Student{
	private:
		int grade;
		float gpa;
	public:
		Student(){
			grade = 100;
			gpa = 5.0;
			cout<<grade<<" "<<gpa<<" "<<endl;
		}
};
class Teacher{
	private:
		int salary;
	public:
		Teacher(){
			salary = 30000;
			cout<<salary<<endl;
		}
};
class Pair{
	private:
		int meeting;
//组合
		Student s;//创建2 
		Teacher t;//创建3 
	public:
		Pair(){
			meeting = 0;
			cout<<meeting<<endl;
		}
};
int main(){
	Pair p;//创建1 
}

6.拷贝构造函数

一般拷贝构造函数的结构

Student (Student &s) //有一个&

1)使用指针

当private里面是指针时,使用new分配空间 strcpy()

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;
class Person{
	private:
		char *name;
	public:
		Person(char *pname){
			name = new char[strlen(pname) + 1];
			if(pname != 0)
			strcpy(name,pname);
			cout<<"构造:"<<endl;
		}
		//自定义拷贝构造函数 
		Person(const Person &other){
			name = new char[strlen(other.name) + 1];
			if(other.name != 0 )
			strcpy(name,other.name);
			cout<<"拷贝:"<<endl; 
		}
		const char* getName( )const{
			return name;
		}
		~Person(){
			delete[] name;
		}
};
int main(){
	Person p1("A");
	Person p2(p1);// 等价于p2 = p1;
	cout<<p2.getName()<<endl; 
}

输出

构造:

拷贝:

A

2)使用数组

直接复制 ,不用分配空间和删除空间 strncpy()

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;
class Person{
	private:
		char name[40];
	public:
		Person(char *pname = "NoName"){
			strncpy(name,pname,sizeof(name));
			name[sizeof(name) - 1] = '\0';
			cout<<"构造:"<<endl; 
		}
		//自定义拷贝构造函数 
		Person(const Person &other){
			strncpy(name,other.name,sizeof(name);
			name[sizeof(name) - 1] = '\0';
			cout<<"拷贝: "<<endl;
		}
		const char* getName( )const{
			return name;
		}
		~Person(){
			delete name;
		}
};
int main(){
	Person p1("A");
	Person p2(p1);
	cout<<p2.getName()<<endl; 
}

3) 区别strcpy和strncpy

strcpy () 完整的将数组进行复制

strncpy()对于数组中位置多的元素,使用'\0' 进行填充,否则就全部复制,但常常与 name[sizeof(name) - 1 ] = '\0 连用,保证结尾为空字符,字符串完整

7.关于类的数据成员初始化

对于类的数据成员是一般变量的情况,放在冒号后放在函数体中的初始化是一样的

1)赋值操作有两次初始化

class Myclass{
	private:
		int d;
	public:
		Myclass(int i){
			d = i;
		}
}; 

2)成员初始化列表

class Myclass{
	private:
		int d;
	public:
//成员初始化列表
//d 在构造函数体执行之前就已经被初始化为 i
		Myclass(int i) : d(i){
		}
}; 

常常使用于常量和引用变量,因为

它们必须再被声明的同时进行初始化,它们**不能**在之后被赋值。这意味着你不能先声明一个常量或引用变量,然后再给它赋值

class MyClass {
private:
    const int myConst;
    int& myRef;
public:
    MyClass(int value, int& refValue) : myConst(value), myRef(refValue) {
        // 构造函数体
    }
};

相当于进行一次初始化,构造函数的参数值给到后面: 成员的()值中。

class StudentID{
	int value;
	public:
		Student(int id = 0){
			value = id;
		}
};
class Student{
	private:
		char name[20];
		StudentID id;
	public:
		Student(char *pname,int ssID = 0):id(ssID){
			//...
		}
};

三、析构函数

1.析构过程

无返回类型 无参数 生命周期结束后自动调用

析构函数和调用构造函数的相反顺序(栈)

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Student{
	private:
		int grade;
		float gpa;
	public:
		Student(){
			grade = 100;
			gpa = 5.0;
			cout<<grade<<" "<<gpa<<" "<<endl;
		}
	~Student(){
		cout<<"销毁学生类"<<endl; 
	}
};
class Teacher{
	private:
		int salary;
	public:
		Teacher(){
			salary = 30000;
			cout<<salary<<endl;
		}
		~Teacher(){
		cout<<"销毁老师类"<<endl; 
	}
};
class Pair{
	private:
		int meeting;
		Student s;//创建2 
		Teacher t;//创建3 
	public:
		Pair(){
			meeting = 0;
			cout<<meeting<<endl;
		}
		~Pair(){
		cout<<"销毁配对类"<<endl; 
	}
};
int main(){
	Pair p;//创建1 
}

输出 :

100 5

30000

0

销毁配对类

销毁老师类

销毁学生类

2.外部定义成员函数

使用 :: 进行设置

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Student{
	private:
		int grade;
		float gpa;
		int num;
	public:
		Student();
		void Print();
};
Student::Student(){
	grade = 100;
	gpa = 4.2;
	Print();
};
void Student::Print(){
	cout<<grade<<" "<<gpa<<" "<<endl;
}
int main(){
	Student s;
}

四、综合应用(1)

1.学生姓名 和 学号构造

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Student{
	private:
		char name[20];
	    int num;
	public:
		Student(char*,int);
		void Print();
};
Student::Student(char* pname ,int n){
	num = n;
	strncpy(name,pname,sizeof(name));
	name[sizeof(name) - 1] = '\0';
	Print();
};
void Student::Print(){
	cout<<name<<" "<<num<<" "<<endl;
}
int main(){
	Student s("AAB",1);
}

若构造函数传递过程中不提供任何值,则为默认值和python的函数传递有点像

c 复制代码
Student::Student(char* pname = "NoName" ,int n = 0){
	num = n;
	strncpy(name,pname,sizeof(name));
	name[sizeof(name) - 1] = '\0';
	Print();
};//输出:NOName 0

2,学生姓名 和 学号构(进阶)

定义两个类,进行嵌套使用

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;

int id = 0;
class SId{
	private:
		int value;
	public:
		SId(int id = 0){
			cout<<"构建值="<<id<<endl; 
			value = ++id;
		}
		~SId(){
			cout<<"销毁id"<<endl;
			value = --id;
		}
		int GetValue(){
			return value;
		}
};


class Student{
	private:
		char name[20];
	    SId id;//分配变量空间  
	public:
		Student(char*,int);
		void Print();
};
Student::Student(char* pname = "NoName" ,int n = 0){
//无参传递为默认值
	strncpy(name,pname,sizeof(name));
	name[sizeof(name) - 1] = '\0';
	SId id(n);//传入值 
	Print();
};
void Student::Print(){
	cout<<name<<" "<<id.GetValue()<<" "<<endl;
}
int main(){
	Student s("ABC",2);
}

输出:

构建值=0

构建值=2

ABC 1

销毁id

销毁id

上面的方法,初始化浪费空间,

****(常用)****下面在初始化其他类对象时,直接给其他类变量赋值,不用再次申请多余的变量空间

注意使用一个: 进行初始化对象

#include<iostream>
#include<cstring>
using namespace std;

int id = 0;
class SId{
	private:
		int value;
	public:
		SId(int id = 0){
			cout<<"构建值="<<id<<endl; 
			value = ++id;
		}
		~SId(){
			cout<<"销毁id"<<endl;
			value = --id;
		}
		int GetValue(){
			return value;
		}
};


class Student{
	private:
		char name[20];
	    SId id;//分配变量空间  
	    //该处不能初始化其他类的对象 
	public:
		Student(char*,int);
		void Print();
};
Student::Student(char* pname = "NoName" ,int n = 0) :id(n){
	strncpy(name,pname,sizeof(name));
	name[sizeof(name) - 1] = '\0';
	Print();
};
void Student::Print(){
	cout<<name<<" "<<id.GetValue()<<" "<<endl;
}
int main(){
	Student s("ABC",9999);
}

输出:

构建值=9999

ABC 10000

销毁id

五、静态成员变量

静态成员函数和静态成员变量都是属于类并非属于 一个对象(类的实例 ) 可以直接通过对类名进行访问

  • 声明和定义是分开的。静态成员变量在类的定义中声明 ,在类外部进行初始化

    cpp 复制代码
    #include<iostream>
    #include<cstring>
    using namespace std;
    
    class Student{
    	static int noOfStudent;
    	char name[40];
    	public:
    		Student(char* pname="no name"){
    			strncpy(name,pname,40);
    			name [39] = '\0';
    			noOfStudent ++;//1
    		}
    		~Student(){
    			cout<<"销毁"<<endl;
    			noOfStudent--;
    		}
    		static int number(){
    			return noOfStudent;
    		}
    };
    int Student::noOfStudent = 0;
    
    void fn(){
    	Student s1;
    	cout<<"s1构造完毕"<<endl;
    	Student s2;
    	cout<<"s2构造完毕"<<endl;
    	cout<<Student::number()<<endl;
    }
    int main(){
    	fn();
    	cout<<"主函数输出:";
    	cout<<Student::number<<endl;
    }

输出:

s1构造完毕

s2构造完毕

2

销毁

销毁

主函数输出:0

六、友元函数

#include<iostream>
#include<cstring>
using namespace std;

class Person{
	private:
		int age;
	public:
		Person(int age){
			this->age = age;
		}
	friend void showAge(Person &p);
};
void showAge(Person &p){
	cout<<p.age<<endl;
}
int main(){
	Person p(10);
	showAge(p);
}

下面两个为使用友元函数和不使用友元函数的对比

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;

class Animal{
	private:
	    int itsWeight;
		int itsAge;
	public:
		   friend void setValue(Animal & ,int);
		   friend void setValue(Animal& ,int ,int); 
};
void setValue(Animal &ta ,int tw)
{
	ta.itsWeight = tw;
	cout<<ta.itsWeight<<" "<<endl;
}
 void setValue(Animal &ta ,int tw ,int tn){
 	ta.itsWeight = tw;
 	ta.itsAge = tn;
 	cout<<ta.itsWeight<<" "<<ta.itsAge<<" "<<endl;
 }
 int main(){
 	Animal c1,c2;
 	setValue(c1,123);
 	setValue(c2,45,67);
 }

增加访问类中保护数据的成员函数

#include<iostream>
#include<cstring>
using namespace std;

class Animal{
	private:
	    int itsWeight;
		int itsAge;
	public:
		Animal(int tw,int ta){
			itsWeight = tw;
			itsAge = ta; 
		}
		int getWeight(){
			return itsWeight; 
		}
		int getitsAge(){
			return itsAge;
		}
};
 int main(){
 	Animal c1(123,456);
 	cout<<c1.getitsAge()<<" "<<c1.getWeight()<<" "<<endl;
 }

总结

  1. 使用友元, 可以不用增加访问数据的成员函数
  2. 直接定义友元使用,可以不考虑private、和protected的性质

七、继承

使用学生类进行大学生和研究生的继承

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;
class Advisor{
	int noOfMeeting;
};
class Student{
	char name[40];
	float gpa;
	public:
		Student(char *pname = "NoName"){
			strncpy(name,pname,40);
			name[39] = '\0';
			gpa = 0;
		}
		void addCourse(int hours,float grade){
			gpa = (hours + 1 + grade) / 2;
		}
		float getGpa(){
			return gpa;
		} 
		void Print(){
			cout<<name<<" "<<gpa<<endl;
		}
};
class GraduateStudent : public Student{
	private:
		Advisor teacher;
		int grade;
	public:
		int getGrade(){
			return grade;
		}
};
int main(){
	Student s1("Leo");
	GraduateStudent gs;
	s1.addCourse(2,10.0);
	s1.Print();//6
	gs.addCourse(1,4.0);
	cout<<gs.getGpa()<<endl;//3
	gs.Print();//3
}

输出:

Leo 6.5

3

NoName 3

  • 1.public继承
  • 2.private继承,基类的私有还是私有
  • 3.protected的保护还是保护

继承后面可以不看,了解

1.继承和组合

类以另一个类对象作为数据成员------组合

前面代码中学生和老师共同形成Pair已经遇到了

2.多继承

尽可能不使用,容易产生成员模糊性

#include<iostream>
#include<cstring>
using namespace std;
class Bed{
	protected:
		int weight;
	public:
		Bed(){
			weight = 0;
		} 
		void Sleep(){
			cout<<"Sleeping"<<endl;
		}
		int SetWeight(int i){
			weight = i;
			return weight;
		}
};
class Sofa{
	protected:
		int weight;
	public:
		Sofa(){
			weight = 0;
		}
		void Watch(){
			cout<<"Watching"<<endl;
		}
		int SetWeight(int i){
			weight = i;
			return weight;
		}
};
class SleeperSofa : public Bed , public Sofa{
//多继承
	public:
		   SleeperSofa(){
		   } 
		   void FoldOut(){
		   	cout<<"Folding"<<endl;
		   }
};
int main(){
	SleeperSofa ss;
	ss.Watch();
	ss.FoldOut();
	ss.Sleep();
//都有输出SetWeight,但要指明类别,否则模糊
	cout<<ss.Sofa::SetWeight(20);
}

输出:

Watching

Folding

Sleeping

20

3.虚拟继承

还很少见 vritual

区分虚拟函数虚拟继承 ,二者无任何联

家具: 获取重量 设置重量(床、沙发)

床:睡觉

沙发:看电视

沙发床:折叠 (床、沙发)

#include<iostream>
#include<cstring>
using namespace std;
class Furniture{
	int weight;
	public:
		Furniture(){
		}
		void SetWeight(int i){
			weight = i;
		}
		int GetWeight(){
			return weight;
		}
};


//虚拟继承
class Bed : virtual public Furniture{
	public:
		Bed(){
		}
		void Sleep(){
			cout<<"Sleeping"<<endl;
		}
};
class Sofa : virtual public Furniture{
	public:
		Sofa(){
		}
		void WatchTV(){
			cout<<"Watching"<<endl;
		}
};


class SleeperSofa : public Bed,public Sofa{
	public:
		SleeperSofa():Sofa(),Bed(){
			//类成员初始化嵌套 
		}
	void FoldOut(){
		cout<<"Folding"<<endl;
	}
};
int main(){
	SleeperSofa ss;
	ss.FoldOut();
	ss.WatchTV();
	ss.Sleep();
	ss.SetWeight(20);
	cout<<ss.GetWeight()<<endl;
}

4.继承、组合、虚拟的构造顺序

先虚拟后对象,再自己

八、多态

c 复制代码
#include<iostream>
#include<cstring>
using namespace std;
class Base{
	public:
		virtual void fn(){
			cout<<"Base"<<endl;
		}
}; 
class SubClass : public Base{
	public:
		virtual void fn(){//派生类中的virtual可以省略
			cout<<"Subclass"<<endl;
		}
};
int i = 0;
void Test(Base & b){
	b.fn();
	i++;
	cout<<"创建完毕"<<i<<endl;
}
int main(){
	Base bc;
	SubClass sc;
	Test(bc);
	Test(sc);
}

输出

Base

创建完毕1

Subclass

创建完毕2

多态效果 :virtual 虚函数与成员函数完全相同

纯虚函数:被标明,但不具体实现的虚成员函数

virtual void init() = 0

九、运算符重载

1、一元运算符重载(++)

class Counter {
private:
    int count;
public:
    Counter(int c = 0) : count(c) {}

    // 前缀自增运算符重载
    Counter& operator++() {
        ++count;
        return *this;
    }

    // 后缀自增运算符重载
    Counter operator++(int) {
        Counter temp(*this);
        count++;
        return temp;
    }

    void display() const {
        cout << "Count: " << count << endl;
    }
};

int main() {
    Counter c;
    ++c; // 前缀自增
    c.display(); // 输出: Count: 1
    c++; // 后缀自增
    c.display(); // 输出: Count: 2
    return 0;
}

this指针指向当前函数

2.二元运算符重载(+)

c 复制代码
class Complex {
private:
    double real, imag;
public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

    Complex operator+(const Complex& c) const {
        return Complex(real + c.real, imag + c.imag);
    }

    void display() const {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(1.0, 2.0);
    Complex c2(3.0, 4.0);
    Complex c3 = c1 + c2;
    c3.display(); // 输出: 4 + 6i
    return 0;
}

++当二元运算符作为成员函数重载时,第一个操作数是调用该函数的对象,第二个操作数通过参数传递。++

3、赋值运算符重载(=):

c 复制代码
class MyString {
private:
    char* str;
public:
    MyString(const char* s = "") {
        if (s) {
            str = new char[strlen(s) + 1];
            strcpy(str, s);
        } else {
            str = nullptr;
        }
    }

    ~MyString() {
        delete[] str;
    }

    MyString& operator=(const MyString& s) {
        if (this != &s) {
            delete[] str;
            str = new char[strlen(s.str) + 1];
            strcpy(str, s.str);
        }
        return *this;
    }

    void display() const {
        if (str)
            cout << str << endl;
        else
            cout << "Empty string" << endl;
    }
};

int main() {
    MyString s1("Hello");
    MyString s2;
    s2 = s1;
    s2.display(); // 输出: Hello
    return 0;
}
相关推荐
前端组件开发1 小时前
基于uni-app与图鸟UI的移动应用模板构建研究
java·开发语言·前端·ui·小程序·前端框架·uni-app
weixin_8368695202 小时前
Java中的机器学习模型集成与训练
java·开发语言·机器学习
IT数据小能手2 小时前
Python中爬虫编程的常见问题及解决方案
开发语言·爬虫·python
大卫的纯爱战士2 小时前
c++指针和引用之高难度(二)习题讲解
开发语言·c++
小oo呆2 小时前
【机器学习300问】135、决策树算法ID3的局限性在哪儿?C4.5算法做出了怎样的改进?
算法·决策树·机器学习
潜水大王3 小时前
C++轻量级 线程间异步消息架构(向曾经工作的ROSA-RB以及共事的DOPRA的老兄弟们致敬)
c++·架构
画饼校长3 小时前
【C++ Primer Plus学习记录】函数的基本知识
开发语言·c++·学习·visualstudio·软件工程
情系明明3 小时前
使用c++设计一个计算器
数据结构·c++·算法
烛九_阴4 小时前
【讨论C++继承】
开发语言·c++
少年没有乌托邦。4 小时前
C++ 类与对象(中)
c++