1、一、类型、返回值类型 二、参数表、函数重载
2、一、实例化 二、实例化的类型或类类是对象的蓝图,对象是类的实例化
3、const
4、一个 两个
5、一、公有继承 二、私有继承、保护继承
6、抽象类、实例化对象
7、函数模板、类模板
8、try、catch、throw
9、流插入运算符、流提取运算符
10、可以、可以
11、析构函数
程序阅读题:
#include <iostream>
int m = 10;
void a(int n) {
n = 15 / n;
m = m / 2;
}
int main() {
int n = 3;
a(n);
std::cout << "m=" << m << std::endl;
std::cout << "n=" << n << std::endl;
return 0;
}
这段代码的功能如下:
- 包含了iostream头文件以使用输入输出流。
- 定义了一个整型变量m并初始化为10。
- 声明了一个函数a,接受一个整型参数n。
- 在函数a中,将15除以参数n的值赋给n,然后m除以2的结果赋给m。
- 在主函数main中,定义了一个整型变量n并初始化为3。
- 调用函数a,并传入参数n。
- 使用cout输出m的值,并换行。
- 使用cout输出n的值,并换行。
- 返回0,表示程序正常结束。
代码的执行流程如下: - 声明一个整型变量m并初始化为10。
- 定义函数a,接受一个整型参数n。
- 在函数a中,将15除以参数n的值赋给n,然后将m除以2的结果赋给m。
- 在主函数main中,定义一个整型变量n并初始化为3。
- 调用函数a,并将参数n的值传入。
- 使用cout输出m的值为5,并换行。
- 使用cout输出n的值为3,并换行。
- 返回0,表示程序正常结束。
最终输出结果为:
m=5
n=3
这段代码的功能是对变量m和n进行一些计算操作,并输出结果。
答案:m = 5,n = 3; 过程:a(3); ----> { n = 15/3; m = 10/2; } n是在main()函数中声明的,n = 3,所以n = 15/3 = 5,只在函数a()的作用域中n = 5,但是a()是 void 类型,没有返回值,因此,回到main()函数中后,n仍然等于3。而m是全局变量,在整个程序的任何一个地方更改m的值,m的值都将改变,因此a()函数改变m的值后,main()函数中的m的值也发生了相应的改变。所以 ,调用a(3)后,在main()函数中输出cout<<m<<" "<<n<<endl; 结果为: 5 3
#include <iostream>
using namespace std;class PP {int x, y;
public:PP() {x = 3;y = 5;}PP(int i, int j) {x = i - y - j;}void Messages() {cout << "x=" << x << " y=" << y << endl;}
};int main() {PP* p1 = new PP();PP p2(3, 4);p2.Messages();p1->Messages();delete p1; // 释放动态分配的内存return 0;
}
这段代码的分析过程如下:
- 包含了iostream头文件以使用输入输出流。
- 使用了
using namespace std
来避免每次都需要写std::
前缀。 - 声明了一个名为PP的类。
- 在PP类中,定义了私有成员变量x和y。
- 提供了两个构造函数:一个无参构造函数,用于初始化x和y的值为3和5;一个有参构造函数,用于将传入的参数分别赋值给x和y。
- 定义了一个名为Messages的成员函数,用来输出x和y的值。
- 定义了主函数main。
- 在主函数中,通过使用new关键字动态地创建了一个PP类的对象p1,并调用了其无参构造函数。这里使用了指针p1来存储对象的地址。
- 创建了一个PP类的对象p2,并调用了其有参构造函数,传入参数3和4。对象p2会在栈上分配内存。
- 调用p2的Messages函数,输出x和y的值,即输出"x=3 y=4"。
- 通过指针p1调用Messages函数,输出x和y的值,即输出"x=3 y=5"。
- 使用delete关键字释放动态分配的内存,即释放p1指向的对象的内存。
- 返回0,表示程序正常结束。
最终输出结果为:
x=3 y=4
x=3 y=5
该代码主要展示了类的定义与使用。其中,类PP包含了两个构造函数、两个私有成员变量和一个成员函数。在主函数中,通过对象和指针分别创建并使用了PP类的实例。通过调用成员函数Messages,可以输出对象的成员变量x和y的值。最后,通过delete关键字释放了通过new关键字动态分配的内存,以避免内存泄漏。
分析一下过程#include <iostream>
using namespace std;
class A {
int a;
public:
A(int aa = 0) : a(aa) {
cout << a << " ";
}
~A() {
cout << "析构";
}
};
int main() {
A x[2] = {2};
cout << endl;
return 0;
}
这段代码的分析过程如下:
- 包含了iostream头文件以使用输入输出流。
- 使用了
using namespace std
来避免每次都需要写std::
前缀。 - 声明了一个名为A的类。
- 在A类中,定义了一个私有成员变量a。
- 提供了一个构造函数A,其中使用了参数的默认值0,用于初始化a的值。构造函数会输出a的值。
- 定义了一个析构函数~A,用于在对象被销毁时输出一条提示信息。
- 定义了主函数main。
- 在主函数中,创建了一个名为x的A类对象数组,数组大小为2。数组中的第一个对象会调用构造函数,并将参数2传入进行初始化。构造函数会输出2。数组中的第二个对象会使用参数的默认值0进行初始化。构造函数会输出0。
- 在主函数中,输出一个空行。
- 返回0,表示程序正常结束。
最终输出结果为:
2 0 析构析构
代码的执行过程如下:
- 主函数开始执行。
- 创建一个名为x的A类对象数组,数组大小为2。
- 数组中的第一个对象会调用构造函数A(2),因此构造函数会输出2。
- 数组中的第二个对象会使用参数的默认值0进行初始化,因此构造函数会输出0。
- 在主函数中,输出一个空行。
- 主函数执行完毕,对象数组x会被销毁,先销毁第二个对象(析构函数输出"析构"),再销毁第一个对象(析构函数输出"析构")。
因此,最终的输出结果是"2 0 析构析构"。(** 析构析构中间没有空!!!**)
#include <iostream>
using namespace std;class A {int a, b;public:A() {a = 0;b = 0;}A(int m) {a = m;b = 0;}A(int m, int n) {a = m;b = n;}void print() {cout << "a=" << a << " b=" << b << endl;}
};int main() {A a, a2(5), a3(5, 15);a.print();a2.print();a3.print();return 0;
}
修正后的代码的运行结果为:
a=0 b=0
a=5 b=0
a=5 b=15
代码的执行过程如下:
- 包含了iostream头文件以使用输入输出流。
- 使用了
using namespace std
来避免每次都需要写std::
前缀。 - 声明了一个名为A的类。
- 在A类中,定义了两个私有成员变量a和b。
- 提供了三个构造函数:
- 默认构造函数A(),将a和b都初始化为0。
- 构造函数A(int m),将a初始化为m,b初始化为0。
- 构造函数A(int m, int n),将a初始化为m,b初始化为n。
- 定义了一个成员函数print(),用于输出a和b的值。
- 定义了主函数main。
- 在主函数中,分别创建了三个A类对象a、a2和a3,分别使用了不同的构造函数进行初始化。
- 依次调用a、a2和a3的print()函数,分别输出a和b的值。
- 返回0,表示程序正常结束。
因此,最终的运行结果为:
a=0 b=0
a=5 b=0
a=5 b=15
#include <iostream>
using namespace std;class A {
public:A() {cout << "generate class A" << endl;}~A() {cout << "destroy class A" << endl;}
};class B : public A {
public:B() {cout << "generate class B" << endl;}~B() {cout << "destroy class B" << endl;}
};int main() {B b;return 0;
}
这段代码定义了两个类A和B,并在主函数中创建了一个B类对象b。类A和类B都定义了构造函数和析构函数,并且类B继承自类A。
在程序执行过程中,首先创建了一个B类对象b。由于B类是A类的子类,因此在创建B类对象时,会先调用A类的构造函数,然后再调用B类的构造函数。因此,首先输出"generate class A",然后输出"generate class B"。
当程序执行完毕时,会先销毁B类对象b,调用B类的析构函数,输出"destroy class B",然后调用A类的析构函数,输出"destroy class A"。
因此,最终的运行结果为:
generate class A
generate class B
destroy class B
destroy class A
#include <iostream>
using namespace std;
class Base {
int x;
public:
virtual void Set(int b) {
x = b;
cout << "x=" << x << endl;
}
};
class Derived : public Base {
protected:
int y;
public:
void Set(int d) {
y = d;
cout << "y=" << y << endl;
}
};
int main() {
Base Bobj;
Derived Dobj;
Base* p;
p = &Bobj;
p->Set(100);
p = &Dobj;
p->Set(200);
return 0;
}
这段代码定义了两个类Base和Derived,并在主函数中创建了一个Base类对象Bobj和一个Derived类对象Dobj。类Base和类Derived都定义了函数Set,并且类Derived继承自类Base。
在程序执行过程中,首先创建了一个Base类对象Bobj和一个Derived类对象Dobj。
接下来,声明了一个Base指针变量p,并将p指向Bobj。然后通过p调用Set(100)函数,由于Set函数是虚函数,所以会根据指针指向的对象类型调用相应的函数。这里p指向的是Base类对象Bobj,所以调用了Base类的Set函数,输出"x=100"。
然后,将p指向Dobj。再次通过p调用Set(200)函数,同样根据指针指向的对象类型调用相应的函数。这里p指向的是Derived类对象Dobj,所以调用了Derived类的Set函数,输出"y=200"。
因此,最终的运行结果为:
x=100
y=200
#include <iostream>
using namespace std;template <class T>
T min(T x, T y) {cout << "function1: ";return (x <= y) ? x : y;
}int min(int x, int y) {cout << "function2: ";return (x < y) ? x : y;
}int main() {int i = 5, j = 6;double d = 1.22, f = 13.21;cout << min(i, j) << endl;cout << min(d, f) << endl;cout << min(d, i) << endl;return 0;
}
这段代码定义了一个函数模板min
和一个重载的min
函数。函数模板min
可以接受任意类型的参数,而重载的min
函数只接受两个int类型的参数。
在主函数中,创建了两个int类型的变量i和j,并分别初始化为5和6。还创建了两个double类型的变量d和f,并分别初始化为1.22和13.21。
接下来,使用cout输出调用min(i, j)
的结果,由于传入的是两个int类型的参数,因此调用的是重载的min
函数,输出"function2: 5"。
然后,使用cout输出调用min(d, f)
的结果,由于传入的是两个double类型的参数,因此调用的是函数模板min
,输出"function1: 1.22"。
最后,使用cout输出调用min(d, i)
的结果,由于传入的是一个double类型和一个int类型的参数,因此调用的是函数模板min
,输出"function1: 1.22"。
因此,最终的运行结果为:
function2: 5
function1: 1.22
function1: 1.22
#include <iostream>
#include <iomanip>using namespace std;int main() {int k = 11;cout << "k=" << hex << k << endl;float d = 12.34144;cout << "d=" << setw(10) << setprecision(5) << setfill('*') << dec<< d << endl;return 0;
}
给出的代码是正确的。以下是代码的执行过程和运行结果:
- 包含了iostream和iomanip头文件以使用输入输出流和格式化输出的函数。
- 使用了
using namespace std
来避免每次都需要写std::
前缀。 - 定义了主函数
main
。 - 声明了一个int类型的变量k,并初始化为11。
- 使用cout输出"k=",然后使用hex表示输出k的十六进制形式,输出结果为b。
- 声明了一个float类型的变量d,并初始化为12.34144。
- 使用cout输出"d=",然后使用setw(10)表示输出宽度为10个字符,使用setprecision(5)表示保留小数点后5位,使用setfill(‘‘)表示填充字符为’’。
- 使用dec表示以十进制格式输出。
- 最后使用cout输出d的值,输出结果为"*****12.34144"。
因此,最终的运行结果为:
k=b
d=*****12.34144
#include <iostream>class A {int x;public:A() {x = 2;}void print() {std::cout << "x = " << x << std::endl;}void operator++() {x += 5;}void operator--() {x -= 2;}
};int main() {A a;++a;a.print();--a;a.print();return 0;
}
这段代码定义了一个类 A
,并在 main()
函数中使用该类。
类 A
包含一个私有成员变量 x
,默认初始化为 2。类 A
还定义了以下成员函数:
print()
函数用于输出变量x
的值。operator++()
重载了前置递增运算符,将变量x
的值增加 5。operator--()
重载了前置递减运算符,将变量x
的值减少 2。
在 main()
函数中,首先创建了一个类 A
的对象 a
,调用构造函数初始化 x
的值为 2。接着,通过 ++a
将 x
的值增加 5,并调用 a.print()
输出结果。然后,通过 --a
将 x
的值减少 2,并再次调用 a.print()
输出结果。
所以,程序的输出结果应为:
x = 7
x = 5
代码逻辑比较简单,它主要演示了对类 A
进行成员函数重载和对对象进行递增和递减操作的功能。
#include <iostream>class Base {int x, y;public:Base(int x, int y) : x(x), y(y) {}void Move(int m, int n) {x += m;y += n;}void Show() {std::cout << "Base(" << x << "," << y << ")" << std::endl;}
};class Derived : private Base {int x1, yl;public:Derived(int i, int j, int m, int n) : Base(i, j), {x1=m, yl=n;}void Show() {std::cout << "Next(" << x1 << "," << yl << ")" << std::endl;}void Move{Move(2,3);}void Show1() {Base::Show();Show();}
};int main() {Base b(1, 2);b.Show();Derived d(3, 4, 10, 15);d.Move1();d.Show();d.Show1();return 0;
}
这段代码定义了两个类 Base
和 Derived
,并在 main
函数中创建了对象进行测试。
首先,让我们逐行分析代码:
#include <iostream>
这一行代码包含了标准输入输出流库,使得我们可以使用 std::cout
来输出信息。
接下来是类 Base
的定义:
class Base {int x, y;public:Base(int x, int y) : x(x), y(y) {}void Move(int m, int n) {x += m;y += n;}void Show() {std::cout << "Base(" << x << "," << y << ")" << std::endl;}
};
类 Base
有两个私有成员变量 x
和 y
,表示整数坐标。构造函数 Base(int x, int y)
用于初始化这两个成员变量。成员函数 Move(int m, int n)
将 x
和 y
分别增加 m
和 n
。成员函数 Show()
输出 x
和 y
的值。
接下来是类 Derived
的定义:
class Derived : private Base {int x1, y1;public:Derived(int i, int j, int m, int n) : Base(i, j), x1(m), y1(n) {}void Show() {std::cout << "Next(" << x1 << "," << y1 << ")" << std::endl;}void Move() {Base::Move(2, 3);}void ShowAll() {Base::Show();Show();}
};
类 Derived
私有继承自 Base
,意味着 Derived
类中的成员函数可以访问 Base
类的公有成员函数。类 Derived
有两个私有成员变量 x1
和 y1
,表示另外一组整数坐标。构造函数 Derived(int i, int j, int m, int n)
初始化基类 Base
的成员变量,以及派生类 Derived
自己的成员变量。成员函数 Show()
输出派生类的坐标。成员函数 Move()
调用基类 Base
的 Move()
函数,并传递参数 (2, 3)
来增加 Base
对象的坐标。成员函数 ShowAll()
先调用基类 Base
的 Show()
函数,然后再调用派生类 Derived
的 Show()
函数。
最后是 main
函数:
int main() {Base b(1, 2);b.Show();Derived d(3, 4, 10, 15);d.Move();d.Show();d.ShowAll();return 0;
}
在 main
函数中,首先创建了一个 Base
对象 b
,并调用其成员函数 Show()
输出 (1, 2)
。接下来,创建了一个 Derived
对象 d
,并通过构造函数进行初始化。然后,调用 d.Move()
函数,使得基类 Base
的坐标增加 (2, 3)
。接着,调用 d.Show()
输出派生类 Derived
的坐标 (10, 15)
。最后,调用 d.ShowAll()
函数,先输出基类 Base
的坐标 (1, 2)
,然后输出派生类 Derived
的坐标 (10, 15)
。
根据代码的逻辑,以下是程序运行后的输出结果:
Base(1, 2)
Next(10, 15)
Base(3, 4)
Next(10, 15)
首先,使用 Base
类创建对象 b
,然后调用 b.Show()
输出 (1, 2)
。
接着,使用 Derived
类创建对象 d
,并传入参数 (3, 4, 10, 15)
进行初始化。然后,调用 d.Move()
函数,将基类 Base
的坐标增加 (2, 3)
。
接下来,调用 d.Show()
输出派生类 Derived
的坐标 (10, 15)
。
最后,调用 d.ShowAll()
函数,先输出基类 Base
的坐标 (3, 4)
,然后输出派生类 Derived
的坐标 (10, 15)
。
请注意,由于类 Base
的成员函数 Move()
和 Show()
都没有声明为虚函数,因此在通过基类指针或引用调用这些函数时将无法实现多态性。在这个例子中,直接通过对象调用了相应的函数,而不是通过指针或引用。
程序填空
#include <iostream>class A {
public:
——————————————————int x, y;public:A(int i, int j) : x(i), y(j) {}void Show() {std::cout << "x: " << x << ", y: " << y << std::endl;}
};int main() {A a(1, 2);a.Show(); // 调用 Show() 成员函数输出对象的坐标信息return 0;
}
程序设计题(共20分)
编写一个输出学校教师和后勒职员信息的程序。设计基类People,属性包括“工号”和“姓名”:派生类教师类Teacher和后勒职员类worker中分别新增属稚“职称”和“工龄”,并设计主函数进行测试。要求:
1,定义构造函数和输出成员函数:
2.使用扩充继承实现派生类人员信息的输出。
根据你的需求,我为你提供了一个满足要求的 C++ 程序示例:
#include <iostream>
#include <string>// 基类 People
class People {
protected:int id; // 工号std::string name; // 姓名public:People(int id, const std::string& name): id(id), name(name) {}// 输出成员函数void display() const {std::cout << "工号: " << id << std::endl;std::cout << "姓名: " << name << std::endl;}
};// 派生类 Teacher
class Teacher : public People {
private:std::string title; // 职称public:Teacher(int id, const std::string& name, const std::string& title): People(id, name), title(title) {}// 输出成员函数(覆盖基类的 display 函数)void display() const {People::display(); // 先调用基类的 display 函数std::cout << "职称: " << title << std::endl;}
};// 派生类 Worker
class Worker : public People {
private:int workYears; // 工龄public:Worker(int id, const std::string& name, int workYears): People(id, name), workYears(workYears) {}// 输出成员函数(覆盖基类的 display 函数)void display() const {People::display(); // 先调用基类的 display 函数std::cout << "工龄: " << workYears << "年" << std::endl;}
};int main() {People p(1, "张三");p.display();std::cout << std::endl;Teacher t(2, "李四", "教授");t.display();std::cout << std::endl;Worker w(3, "王五", 5);w.display();std::cout << std::endl;return 0;
}
在这个程序中,定义了一个基类 People
,以及两个派生类 Teacher
和 Worker
,并实现所需的构造函数和输出成员函数。基类 People
包含工号和姓名属性,并提供了 display
函数用于输出成员信息。派生类 Teacher
和 Worker
分别新增了职称和工龄属性,并通过覆盖 display
函数实现了派生类成员信息的输出。
在 main
函数中,创建了一个基类 People
的对象 p
,以及两个派生类对象 Teacher
和 Worker
的对象 t
和 w
。分别调用它们的 display
函数,输出各自的成员信息。
程序输出结果为:
工号: 1
姓名: 张三工号: 2
姓名: 李四
职称: 教授工号: 3
姓名: 王五
工龄: 5年
当你运行这个程序时,它将创建一个基类 People
的对象 p
,并使用构造函数初始化工号为1,姓名为"张三"。然后调用 display
函数输出该对象的成员信息:
工号: 1
姓名: 张三
接下来,程序创建一个派生类 Teacher
的对象 t
,并使用构造函数初始化工号为2,姓名为"李四",职称为"教授"。由于 Teacher
类中覆盖了基类 People
的 display
函数,所以在调用 t.display()
时会先调用基类的 display
函数,输出工号和姓名,然后再输出职称:
工号: 2
姓名: 李四
职称: 教授
然后,程序创建一个派生类 Worker
的对象 w
,并使用构造函数初始化工号为3,姓名为"王五",工龄为5年。同样地,由于 Worker
类中覆盖了基类 People
的 display
函数,所以在调用 w.display()
时会先调用基类的 display
函数,输出工号和姓名,然后再输出工龄:
工号: 3
姓名: 王五
工龄: 5年
这样,程序通过扩充继承实现了输出不同类的人员信息,并且派生类中新增的属性也得以正确输出。
这个程序示例展示了面向对象编程中的继承和多态的概念。基类 People
定义了所有人员共有的属性和行为,而派生类 Teacher
和 Worker
在继承基类的同时增加了各自独有的属性,并通过覆盖基类的函数实现了特定的行为。这种设计使得我们可以在统一的接口下操作不同类型的对象,并根据对象的实际类型调用对应的函数。
在这个程序中,我们使用了面向对象编程的三大特性之一:继承。通过继承,派生类可以从基类继承属性和方法,并且可以添加自己的额外属性和方法。这使得我们可以利用代码的复用性,避免重复编写相似的代码。
在示例中,Teacher
类和 Worker
类分别是基类 People
的派生类。它们继承了 People
类中的成员变量 id
和 name
,并分别新增了属于自己的成员变量 title
和 workYears
。
为了实现继承,我们使用了 public
访问修饰符来指定派生类对基类成员的访问权限。具体来说,在 Teacher
类和 Worker
类的定义中,我们使用 : public People
将它们声明为公有继承关系。
此外,在 Teacher
类和 Worker
类中,我们还覆盖(override)了基类 People
中的 display
函数。通过使用相同的函数名称和签名,派生类可以重写(override)基类中已经存在的函数,并且通过关键字 override
明确表明这是对基类函数的重写。在派生类中,我们先调用基类的 display
函数,然后再在输出中添加额外的信息,实现了对派生类的特定输出。
这个示例还展示了多态(polymorphism)的概念。多态允许我们通过基类指针或引用来操作派生类对象,以达到统一的接口。在 main
函数中,我们创建了基类 People
的对象 p
,以及派生类 Teacher
和 Worker
的对象 t
和 w
。然后,我们分别调用它们的 display
函数,尽管它们的类型不同,但由于多态性,它们都会调用正确的成员函数来输出各自的信息。
总结起来,继承和多态是面向对象编程中非常重要的概念。它们提供了代码的组织和重用的机制,使得程序更加灵活和可扩展。通过继承,我们可以构建出更丰富的类层次结构,通过多态,我们可以以统一的方式操作不同类型的对象。