C++期末整理

发布于:2024-07-06 ⋅ 阅读:(51) ⋅ 点赞:(0)

课堂笔记

构造与析构

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

struct Date
{
	int y, m, d;
	void setDate(int, int, int);
	Date(int yy, int mm, int dd) {y = yy, m = mm, d = dd;}
};

class Student
{
private:
	char* name;
	Date birthday;
public:
	// 如果没写不带参数的构造函数,系统会提供一个不带参数的构造函数,称为缺省构造函数,或者是拷贝构造函数
	Student(const Student&); // 拷贝构造函数,当有new和delete的时候要写
	Student():birthday(2000, 3, 4) {} // 不带参数的构造函数
	Student(char*, int, int, int);
	~Student() {delete []name;} // 与构造函数成对出现
};

Student::Student & operator = (const Student &s1) // 运算符重载函数
{
	name = new char[strlen(s1.name) + 1];
	strnpy(name, s1.name, strlen(s1.name));
	birthday = s1.birthday;
	return *this;
}

Student::Student(const Student &s1) // 拷贝构造函数
	:birthday(s1.birthday) // 初始化
{
	// name = s1.name; // 错误 
	name = new char[strlen(s1.name) + 1];
	// name = s1.name; 错误,没用到新开辟的空间
	strncpy(name, s1.name, strlen(s1.name));
}

Student:: Student(char* p, int y, int m, int d)
	: birthday(y, m, d) // 初始化
{
	// name = p; 不好,指针会改变
	// name = new char[sizeof(p)]; // 指针的大小,一般为8个字节,但不是字符串的长度
	name = new char[strlen(p) + 1]; // 多一个位置存放'\0'
	strncpy(name, p, strlen(p));
};

void print(Student s)
{
	cout << s,name << endl; // error,私有的,不能访问
}

int main()
{
	const char *p = "zhangsan";
	Student s1((char*)p, 2000, 3, 4); // 强制类型转换
	// Student *s;
	// s = new Student[10000]; // 调用不带参数的构造函数10000次
	Student s2(s1); // 调用拷贝构造函数
	// print(s1); // 也会调用拷贝构造函数
	Student s3;
	s3 = s1; // 运算符重载

	return 0;
}

静态与友元

#include <iostream>
using namespace std;

class Student;
class Date
{
	string printDate(Student*);
};

int studentCount()
{
	static int count = 0; // 静态变量,一直存在,可以理解成全局变量,生命周期和全局变量一样,但只能在函数中使用
	count++;
	return count;
}

class Student
{
private:
	string name; // 比字符串好操作
	int num;
	int age;
	static int count; // 全班的同学数目
	static int totalage;
public:
	Student(string, int, int);
	void total(); // 成员函数,有一个隐藏的参数,this指针
	static float averageAge(); // 静态函数,无this指针
	// friend是单向的
	friend void print(Student *); // 友元函数,无this指针,一般的,友元函数里面一般有一个参数,指针或者引用
	friend string Date::printDate(Student*);
	friend Date; // Date里边所有的函数都是我的朋友,一般不建议
};

Student::Student(string name1, int num1, int age1)
	:name(name1), num(num1);
{
	age = age1; // 和上面的初始化方法的结果及作用相同
}

void Student::total()
{
	totalage += age;
	count++;
}

float Student::averageAge() // 静态函数
{
	// cout << age; // error,静态函数不能访问类里边的age变量,因为没有this指针
	return totalage / count;
}

int Student::count = 0; // 静态变量的初始化
int Student::totalage = 0;

void print(Student *s) // 全局函数,参数*s也可以写成&s,下面的"->"改成"."
{
	s.name = string("class") + s.name; // 可以修改类里面的私有变量的值
	cout << s -> name
		 << s -> num
		 << s -> age;
}

int main()
{
	Student s[3] = {
		Student("zhang", 202301, 18),
		Student("li", 202302, 19),
		Student("wang", 202303, 18)};

	for (int i = 0; i < 3; i++)
	{
		s[i].total();
	}
	
	Student st0(s[0]);
	Student st1("liu", 202304, 17);
	st1 = st0;

	cout << "average age = " << Student::averageAge(); // 调用静态函数的标准写法
	cout << "average age = " << s[0].averageAge(); // 也是正确的,但是不建议用,具有误导性

	return 0;
}

string

#include <iosteam>
using namespace std;

int main()
{
	string s1;
	string s2("hello world\n");
	cout << s2[4]; // 打印s2里边的第四个字符,也是一个函数,运算符函数
	s1 = s1 + s2;
	cout << s1;
}

继承

#include <iostream>
using namespace std;

class Student
{
private:
protected: // 继承者可以访问
	string name; // 比字符串好操作
	int num;
	int age;
public:
	// 当父类的构造函数被调用时,它的子类构造函数会被自动调用,跟析构函数的调用相反
	Student(string, int, int);
	void print1() {cout << name << num << age;}
	~Student() {cout << "Destruct Student\n";}
};

Student::Student(string name1, int num1, int age1)
	:name(name1), num(num1);
{
	age = age1; // 和上面的初始化方法的结果及作用相同
	cout << "Construct Student\n";
}

class IOTStudent : public Student // 常用public表示继承,如果不写public,则默认为private,但是也没有意义
{
private:
	int cpp;
public:
	IOTStudent(string, int, int, int, int);
	void print() {cout << name << num << age << cpp;} // 可以访问父类的变量,如果是private则不可以访问
	// 所有的子类被调用析构函数时,他的父类析构函数也会被自动调用
	~IOTStudent() {cout << "Destruct IOTStudent\n";}
};

// 子类必须为父类提供参数
IOTStudent::IOTStudent(string name1, int num1, int age1, int cpp)
	: Student(name1, num1, age1) // 调用Student的有参构造函数
{
	cpp = cpp1;
	cout << "Construct IOTStudent\n";
}

void f(Student *p) // 根据p的数据类型来判断调用什么输出函数
{
	p->print();
}

int main()
{
	// 指针不会产生构造函数
	// 父类的指针比较好用
	Student s1("zhang", 20230001, 19), *p1; // p1不会调用构造和析构函数
	IOTStudent s2("li", 20230002, 19, 86), *p2; // s2先调用一个父类的构造函数,再构造子类的构造函数
	// 先调用s2的子类的析构函数,再调用s2的父类的析构函数,最后调用s1的父类的析构函数

	f(&s1); // 打印父类的打印函数
	f(&s2); // 打印父类的打印函数,因为静态联编

	p1 = &s1;
	p1->print(); // 打印出父类的打印函数
	p1 = &s2;
	/* 还是打印父类的打印函数,因为p1是Student类型的指针变量,
	静态编译,此时编译器不知道p1指向的是哪一个地方,编译器只能通过p1的数据类型来判断指向哪一片区域*/
	p1->print();
	IOTStudent *p2;
	p2 = &s2; // 不能指向s1
	p2->print(); // 想要调用子类的打印函数只能通过定义一个子类的数据类型的变量

	s1 = s2; // right,但是没有实用价值
	p1 = &s1; // 取s1的地址
	p2 = &s2;
	p1 = &s2; // right
	p2 = &s1; // error,子类的指针指向父类的地址是错误的,cpp会变成随机数
	p1 = p2; // right
	p2->print(); 
	s2 = s1; // error,最后一个cpp的空间为随机数

	cout << "size of Student is:" << sizeof(Student) << endl;
	cout << "size of IOTStudent is:" << sizeof(IOTStudent) << endl;
	cout << s2.name; // error

	s2.print(); // 打印IOTStudent里的打印函数(就近原则)
	s2.print1(); // 打印Student里的打印函数,可以调用父类的函数,可以通过改函数名来区分
	s2.Student::print(); // 指定调用STudent父类里边的打印函数,"::"表示预操作符

	return 0;
}

动态联编

#include <iostream>
using namespace std;

class Student
{
private:
protected: // 继承者可以访问
	string name; // 比字符串好操作
	int num;
	int age;
public:
	// 当父类的构造函数被调用时,它的子类构造函数会被自动调用,跟析构函数的调用相反
	Student(string, int, int);
	// 动态联编,或者是多态
	// 需要父类和子类的函数头,参数完全相同
	virtual void print() {cout << name << num << age;} // 虚函数,父类的函数是虚函数,子类的相同的函数也是虚函数
	~Student() {cout << "Destruct Student\n";}
};

Student::Student(string name1, int num1, int age1)
	:name(name1), num(num1);
{
	age = age1; // 和上面的初始化方法的结果及作用相同
	cout << "Construct Student\n";
}

class IOTStudent : public Student // 常用public表示继承,如果不写public,则默认为private,但是也没有意义
{
private:
	int cpp;
public:
	IOTStudent(string, int, int, int, int);
	virtual void print() {cout << name << num << age << cpp;} // 可以访问父类的变量,如果是private则不可以访问
	// 所有的子类被调用析构函数时,他的父类析构函数也会被自动调用
	~IOTStudent() {cout << "Destruct IOTStudent\n";}
};

// 子类必须为父类提供参数
IOTStudent::IOTStudent(string name1, int num1, int age1, int cpp)
	: Student(name1, num1, age1) // 调用Student的有参构造函数
{
	cpp = cpp1;
	cout << "Construct IOTStudent\n";
}

void f(Student *p) // 根据p的数据类型来判断调用什么输出函数
{
	p->print();
}

int main()
{
	// 指针不会产生构造函数
	// 父类的指针比较好用
	Student s1("zhang", 20230001, 19), *p1; // p1不会调用构造和析构函数
	IOTStudent s2("li", 20230002, 19, 86), *p2; // s2先调用一个父类的构造函数,再构造子类的构造函数
	// 先调用s2的子类的析构函数,再调用s2的父类的析构函数,最后调用s1的父类的析构函数

	Student *p1;
	p1 = &s2;
	f(p1); // 调用父类的函数输出
	IOTStudent *p2;
	p2 = &s2;
	f(p2); // 调用父类的函数输出,因为输出什么类型唯一的判断标准是f函数的参数类型

	// 希望这个指针所指向的对象是什么类型的,就调用什么类型的输出函数,就需要使用动态联编,virtual
	Student *p;
	p = &s1;
	p -> print();
	p = &s2;
	p -> print();

	return 0;
}

动态联编的例子

#include <iostream>
using namespace std;

class Shape
{
protected:
	double L, H;
public:
	void init() {
		cout << "input L=";
		cin >> L;
		cout << "input H=";
		cin >> H;}
	/*如果在基类里面有纯虚函数,则他的派生类必须实现这个函数,如果不实现,则编译会报错且基类不能有实例
	e.g. 
	Shape s; // error
	s.area(); // error
	*/
	virtual double area() = 0; // 不是返回0的意思,意思是不写这个函数,也叫纯虚函数
};

class Tr : public Shape // 三角形
{
public:
	virtual double area() {return L * H / 2;}
};

class Re : public Shape // 矩形
{
public:
	virtual double area() {return L * H;}
};

class Ci : public Shape // 圆
{
public:
	virtual double area() {return 3.14 * 3.14 * L;}
};

int main()
{
	Shape *p; // 父类指针好用
	for (int i = 0; i < 5; i++)
	{
		char c;
		cout << "\ninput shape type";
		cin >> c;
		if (c == 'T')
		{
			p = new Tr;
		}
		else if (c == 'R')
		{
			p = new Re;
		}
		else if (c == 'C')
		{
			p = new Ci;
		}
		else
		{
			break;
		}
		p->init(); // 初始化,在函数中输入长度和宽度
		cout << "\narea of p is:" << p->area();
	}
	delete p;

	return 0;
}

+±-重载

#include <iostream>
using namespace std;

class Complex
{
private:
	double x, y;
public:
	Complex(double xx = 0, double yy = 0); // 如果不写参数,则默认他的xx和yy都默认为0,默认调用缺省构造函数
	void print();
	Complex& operator++();
	Complex operator++(int);
	friend Complex& operator--(Complex& c);
};

Complex::Complex(double xx = 0, double yy = 0) // 如果不写参数,则默认他的xx和yy都默认为0
{
	x = xx;
	y = y;
}

void Complex::print()
{
	cout << x;
	if (y > 0)
	{
		cout << "+" << y << 'i';
	}
	else if (y < 0)
	{
		cout << y << 'i';
	}
}

Complex& operator++()
{
	x++;
	return *this;
}

Complex Complex::operator++(int) // 不能返回引用,因为生存周期问题,函数结束后,指针消失,所以不能返回一个指针
{
	Complex temp(*this); // 把自己拷贝
	x++;
	return temp;
}

Complex& operator--(Complex& c)
{
	c.x -= 1;
	return c;
}

int main()
{
	Complex c2(1.1, -2.2);

	++c2; // 调用函数Complex& operator++();
	cout << c2 << endl;
	c2++; // 调用函数Complex operator++(int)
	cout << c2;

	--c2;
	cout << c2;

	return 0;
}

函数模板

// 函数的模板放在.h文件里面
#include <iostream>
using namespace std;

class Complex
{
private:
	double x, y;
public:
	Complex(double xx = 0, double yy = 0); // 如果不写参数,则默认他的xx和yy都默认为0,默认调用缺省构造函数
	bool operator> (Complex& c);
	friend ostream& operator<< (ostream&, const Complex&);
};

Complex::Complex(double xx = 0, double yy = 0) // 如果不写参数,则默认他的xx和yy都默认为0
{
	x = xx;
	y = y;
}

Complex operator>(bool& c) 
{
	return (x * x + y * y > c.x * c.x + c.y * c.y) ? this : c;
}

ostream& operator<< (ostream& o, const Complex& c)
{
	o << c.x;
	if (c.y > 0)
	{
		o << '+' << c.y << 'i';
	}
	else if (c.y < 0)
	{
		o << c.y << 'i';
	}
	return o;
}

/*
int Max(int x, int y);
float Max(float x, float y);
char Max(char x, char y);
Complex Max(Complex x, Complex y);

int Max(int x, int y)
{
	return (x > y) ? x : y;
}

float Max(float x, float y)
{
	return (x > y) ? x : y;
}

char Max(char x, char y)
{
	return (x > y) ? x : y;
}
*/

template <typename T1> // 放在头文件里面
T1 Max (T1 x, T1 y)
{
	return (x > y) ? x : y;
}

int Max(int x, int y)
{
	return (x > y) ? x : y;
}

int main()
{
	int i1 = 4, i2 = 6;
	cout << Max(i1, i2) << endl;

	float f1 = 1.2, f2 = 2.3;
	cout << Max(f1, f2) << endl;

	char c1 = 'a', c2 = 'x';
	cout << Max(c1, c2) << endl;

	// cout << Max(i1, f2) << endl; // 调用int Max(int x, int y)函数,做了一个函数重载

	Complex com1;
	// Complex (1);
	com1 = 1; // x = 1, y = 0,实际上调用构造函数,把1传进去

	Complex com(1), com(1.1, 1.2);
	cout << Max(com1, com2) << endl; // <<, >重载

	return 0;
}

类的模板

// 类的模板放在.h文件里面,模板都放在头文件(.h)里面
#include <iostream>
using namespace std;

template <typename T2>
class List
{
private:
	int n;
	T2 *v;
public:
	List(int x);
	~List();
	T2& operator [](int x);
	int search(T2 value);
};

template <typename T2>
List<T2>::List(int x)
{
	n = x;
	v = new T2[n];
}

template <typename T2>
List<T2>::~List()
{
	delete []v; // 如果不写中括号,申请的内存依旧会被释放,有[],会调用n次析构函数,如果没有,只调用一次
}

T2& List<T2>::operator [](int x)
{
	return v[x];
}

template <typename T2>
int List<T2>::search(T2 value)
{
	for (int i = 0; i < n; i++)
	{
		if (v[i] == value) // 在Complex中增加"=="运算符重载
		{
			return i;
		}
	}
	return -1;
}

int main()
{
	typedef List<int> ilist;
	ilist il2(57);
	List<int> il1(57); // 与上式作用相同,同时调用构造函数

	List<float> fl1(58);
	fl1[20] = 5.0;

	List<Complex> c1(59); // 嵌套函数模板

	return 0;
}

//----------------------------------------------分割线---------------------------------------------------------//

template <typename T1>
class Mylnt
{
private:
	T1 t1, t2, t3;
public:
	Mylnt();
	Mylnt(T1 t1_value, T1 t2_value, T1 t3_value);
	T1 getMax();
	T1 getMin();
	void sort();
	void show();
};

template <typename T1>
Mylnt<T1>::Mylnt(T1 t1_value, T1 t2_value, T1 t3_value)
{
	t1 = t1_value;
}

template <typename T1>
T1 Mylnt<T1>::getMax()
{
	T1 max;
	if (t1 >= t2)
	{
		if (t1 > t3)
		{
			max = t1;
		}
		else
		{
			max = t3;
		}
	}
	else
	{
		if (t2 > t3)
		{
			max = t2;
		}
		else
		{
			max = t3;
		}
	}
}

运算符重载

#include <iostream>
using namespace std;

class Complex
{
private:
	double x, y;
public:
	Complex(double xx = 0, double yy = 0); // 如果不写参数,则默认他的xx和yy都默认为0,默认调用缺省构造函数
	void print();
	// 返回一个引用或者指针的话的话,不能返回一个临时变量,因为指针指向一个临时变量的地址,函数结束后,地址消失,堆栈地址失效
	Complex& add(const Complex& c2);
	Complex& operator+=(const Complex& c2); // 运算符重载函数,但是名字固定,功能和上面的函数一样,参数也一样,只是名字不同
	Complex operator+(const Complex& c2); // 有两个参数,但是有一个是他自己,所以省略,返回不写引用
	friend Complex operator-(const Complex& c1, const Complex& c2); // 没有this指针,所以要把对象传进去,多一个他自己参数
};

Complex::Complex(double xx = 0, double yy = 0) // 如果不写参数,则默认他的xx和yy都默认为0
{
	x = xx;
	y = y;
}

void Complex::print()
{
	cout << x;
	if (y > 0)
	{
		cout << "+" << y << 'i';
	}
	else if (y < 0)
	{
		cout << y << 'i';
	}
}

Complex& Complex::add(const Complex& c2) // add函数不允许修改c2的内容,返回一个引用
{
	x += c2.x;
	y += c2.y;
	return Complex(x, y); // error,因为这个变量的生命周期结束了
	return *this; // 把自己传出去
}

Complex& Complex::operator+=(const Complex& c2) // 运算符重载函数,但是名字固定,功能和上面的函数一样,参数也一样,只是名字不同
{
	x += c2.x;
	y += c2.y;
	return *this; // 把自己传出去
}

Complex Complex::operator+(const Complex& c2) // 返回不写引用,因为不希望改c1的内容,
{
	Complex temp;
	temp.x = c2.x + this->x;
	temp.y = c2.y + y;
	return temp;
}

Complex operator-(const Complex& c1, const Complex& c2) // 没有this指针,所以要把对象传进去
{
	Complex t;
	t.x = c1.x - c2.x;
	t.x = x + c2.x; // error,因为没有this指针
	t.y = c1.y - c2.y;
	return t;
}

int main()
{
	Complex c1;
	Complex c2(1.1, -2.2);
	Complex c3(1.3, 4);

	cout << "\nc1="; c1.print;
	cout << "\nc2="; c2.print;
	cout << "\nc3="; c3.print;

	c1.add(c2); // c1 + c2
	cout << "\nafter add(), c1= "; c1.print;
	c1 += c2; // 运算符重载,和上面的实现功能一样,两个参数
	cout << "\nafter +=c2, c1= "; c1.print;

	c3 = c1 + c2; // 等号有缺省的运算符函数,加号没有,两个参数
	cout << "\nafter c3=c1+c2, c3= "; c3.print;

	c3 = c1 - c2; // 使用友元函数

	(c1 + c2 + c3); // 如果operator+(const Complex& c2)函数返回值为void的,则这一行代码错误

	return 0;
}

// 除了感叹号的点,其余有点的运算符都不能做重载

// "?:"运算符
int getmax(int x, int y)
{
	return (x > y) ? x : y;
}

// "&="运算符
c3 = c1 & c2;
c1 &= c2;

M1 = M1 * M2;

输入输出重载

#include <iostream>
using namespace std;

class Complex
{
private:
	double x, y;

public:
	Complex(double xx = 0, double yy = 0);					// 如果不写参数,则默认他的xx和yy都默认为0,默认调用缺省构造函数
	friend ostream &operator<<(ostream &, const Complex &); // 重载<<,只能用友元函数,因为ostream不是Complex类型,所以不能用成员函数实现
	friend istream &operator>>(istream &, Complex &); // 重载>>
};

Complex::Complex(double xx = 0, double yy = 0) // 如果不写参数,则默认他的xx和yy都默认为0
{
	x = xx;
	y = yy;
}

ostream &operator<<(ostream &o, const Complex &c)
{
	o << c.x;
	if (c.y > 0)
	{
		o << "+" << c.y << 'i';
	}
	if (c.y < 0)
	{
		o << c.y << 'i';
	}
	return o;
}

istream &operator>>(istream &, const Complex &)
{

}

int main()
{
	Complex c1;
	Complex c2(1.1, -2.2);
	Complex c3(1.3, 4);

	cout << c1 << c2;

	return 0;
}

期末

// 范围:类,对象和数组,继承,构造,析构,静态
// 虚继承,多态,多重继承,纯虚函数,运算符重载,深拷贝,虚函数

// 纯虚函数,定义一个基类的指针,可以通过这个指针访问子类的函数,前提是父类的同样的函数前面加上virtual,纯虚函数是让父类的函数等于零
// 深拷贝,在类里面拷贝构造,运算符重载的等号
// 对象数组,类里面有一个数组的对象

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

class A
{
private:
    char *name;
    int i;
public:
    // A() {cout << "constuct A";}
    // ~A() {cout << "destruct A";}
    A(const char*);
    ~A();
    A(const A&); // 拷贝构造
    A& operator=(const A&); // 运算符重载
    void print() {cout << "this is class A\n";}
    // virtual void print() {cout << "this is class A\n";}
    // void print() = 0; // 纯虚函数不能有实例,可以有指针,它的子类必须实现这个函数
};

A::A(const char* n)
{
    name = nullptr;
    size_t size = strlen(n);
    name = new char[size + 1];
    cout << "allocate memory for name\n";
    strncpy(name, n, size);
    cout << "construct A : " << name << endl;
}

A::~A()
{
    cout << "destruct A : " << name << endl;
    delete[] name;
}

A::A(const A& a)
{
    // 需要释放最开始构造申请的空间
    if (name != nullptr)
    {
        delete[] name;
    }
    name = a.name; // 错误,此为浅拷贝
    size_t size = strlen(a.name); // 深拷贝,自己申请空间
    strncpy(name, a.name, size);
}

class B : public A
{
public:
    void print() {cout << "this is class B\n";}
};

class C : public A
{
public:
    void print() {cout << "this is class C\n";}
};

class D : public A
{
public:
};

int main()
{
    A *p, b[5];
    p = new A[5];
    cout << b[2].i;
    cout << (*(p + 2)).i;
    delete[] p;

    A a("OOP class"), *ap;
    A b("class 2");
    A b(a); // 调用拷贝构造函数
    A b = a; // 调用拷贝构造函数
    cout << "a.name=" << (void*)a.name << "b,name=" << (void*)b.name << endl; // 打印地址
    a = b; // 析构会出错
    cout << "a.name=" << (void*)a.name << "b,name=" << (void*)b.name << endl;

    // B b;
    // C c;
    // D d; // 错误,因为没有实现print函数
    a.print(); // 打印A的信息
    ap = &a;
    ap -> print(); // 打印A
    // ap = &b;
    ap -> print(); // 打印A,因为是静态联编,根据ap的类型调用其的类的函数,1

    // 动态联编,根据指向的数据类型调用其的函数
    // ap = &b;
    // ap -> print(); // 打印B 

    return 0;
}

比较生日

#include <iostream>
using namespace std;

struct CDate
{
    int y, m, d;
};

class CPerson
{
private:
    CDate birthday;

public:
    bool cmp(CDate c) // 比较谁的年龄更大
    {
        long l1, l2;
        l1 = birthday.y * 10000 + birthday.m * 100 + birthday.d;
        l2 = c.y * 10000 + c.m * 100 + c.d;
        return l1 > l2;
    }
};

int main()
{
    CPerson p1, p2;

    return 0;
}

多重继承

#include <iostream>
using namespace std;

class Person
{
protected:
	string name;
	Person(string n) {name = n;}
}

class Student : virtual public Person // 虚继承
{
protected:
	int id;
public:
	// 如果提供了有参构造函数,系统不会提供缺省构造函数,如果没有提供有参构造函数,则系统会提供一个缺省的构造函数
	Student() : Person("") {} // 派生类必须调用父类的构造函数
	Student(string n, int i) : Person(n), id(i) {cout << "CS\n";} // 标准格式,派生类必须调用父类的构造函数
	~Student() {cout << "DS\n";}
	void print() {cout << name << id;}
};

class Teacher : virtual public Person
{
protected:
	double salary;
public:
	Teacher(string, double) : Person(n){salary = s; cout << "CT\n";} // 不标准
	~Teacher() {cout << "DT\n";}
	void print() {cout << name << salary;}
};

// 先执行Student的构造函数,再执行Teacher的构造函数,先析构Teacher再析构Student,顺序由此决定
class SJ : public Student, public Teacher // 记得加上public,否则默认private
{
public:
	SJ(string, int, double);
	~SJ() {cout << "Dsj\n";}
	void print();
};

SJ::SJ(string n, int i, double s) // 要给父类提供参数,用标准格式初始化
	// 必须给祖先类实现构造函数
	: Person(n), Student(n, i), Teacher(n, s) // 如果不写Student(n, i),则会调用Student的无参构造函数
{
	cout << "Csj\n";
}

void SJ::print()
{
	cout << name << id << name2 << salary;

	print1(); // 结果和上面相同
	print2();

	// 或者预操作
	Student::print();
	Teacher::print();

	cout << name << id << salary; // error,因为有两个类

	// 使用预操作
	cout << Teacher::name << id << salary; // 对

	cout << name << id << salary; // 对
}

int main()
{
	// Student s;
	// Teacher t("zhang", 20000.0);
	SJ sj("li", 20230001, 4000.0);

	return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到