C with classes
This commit is contained in:
BIN
ObjectOrientedProgramming/OOP/oop_hw5/04_面向对象程序设计上机实验四_参考答案.docx
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/04_面向对象程序设计上机实验四_参考答案.docx
Normal file
Binary file not shown.
152
ObjectOrientedProgramming/OOP/oop_hw5/hw1/ans.md
Normal file
152
ObjectOrientedProgramming/OOP/oop_hw5/hw1/ans.md
Normal file
@@ -0,0 +1,152 @@
|
||||
## **1)第一段代码分析:递归构造与输出**
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
A(int n):val(n){}
|
||||
protected:
|
||||
int val;
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
B(int n) :A(n)
|
||||
{
|
||||
pB = (n > 0 ? new B(n-1) : 0);
|
||||
}
|
||||
|
||||
~B() { delete pB; }
|
||||
|
||||
void Display()
|
||||
{
|
||||
cout << val << endl;
|
||||
if (pB != 0)
|
||||
pB->Display();
|
||||
}
|
||||
|
||||
private:
|
||||
B* pB;
|
||||
};
|
||||
```
|
||||
|
||||
### 📌 构造逻辑:
|
||||
|
||||
* `B(4)` 被创建时,会递归构造 `B(3) → B(2) → B(1) → B(0) → B(-1)` 停止(因 `n == 0` 时 `pB = 0`)
|
||||
* 每一层的 `val` 都是当前 `n`
|
||||
|
||||
### 📌 输出逻辑:
|
||||
|
||||
`b.Display()` 调用后会:
|
||||
|
||||
```cpp
|
||||
cout << 4
|
||||
-> Display() on B(3)
|
||||
cout << 3
|
||||
-> Display() on B(2)
|
||||
cout << 2
|
||||
-> Display() on B(1)
|
||||
cout << 1
|
||||
-> Display() on B(0)
|
||||
cout << 0
|
||||
```
|
||||
|
||||
所以最终输出是:
|
||||
|
||||
```
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
0
|
||||
```
|
||||
|
||||
### ✅ **运行结果1**:
|
||||
|
||||
```
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **2)第二段代码分析:构造顺序与拷贝构造**
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
A(int n):num(n) { Out(); }
|
||||
A(const A& rhs):num(rhs.num) { Out(); }
|
||||
void Out() { cout << num << endl; }
|
||||
private:
|
||||
int num;
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
B(A& a) : obj(a), A(1) { }
|
||||
void Out() { obj.Out(); }
|
||||
|
||||
private:
|
||||
A obj;
|
||||
};
|
||||
```
|
||||
|
||||
### 📌 构造顺序注意:
|
||||
|
||||
在 `B(A& a) : obj(a), A(1)` 中,尽管初始化顺序写的是先 `obj`,再 `A`,**但实际构造顺序是:**
|
||||
|
||||
1. 先构造基类 A(即 `A(1)`)
|
||||
2. 再构造成员对象 `obj(a)`(调用拷贝构造函数)
|
||||
|
||||
### 📌 main 函数:
|
||||
|
||||
```cpp
|
||||
A a(8); // 输出:8
|
||||
B b1(a); // 顺序:
|
||||
// A(1) → 输出:1
|
||||
// obj(a) 拷贝构造 → 输出:8
|
||||
B b2(b1); // 和上面类似,只是复制的是 b1 对象的成员 obj
|
||||
// A(1) → 输出:1
|
||||
// obj(b1.obj) 拷贝构造 → 输出:8
|
||||
|
||||
b2.Out(); // 调用 obj.Out() → 输出:8
|
||||
```
|
||||
|
||||
### ✅ **运行结果2**:
|
||||
|
||||
```
|
||||
8
|
||||
1
|
||||
8
|
||||
1
|
||||
8
|
||||
8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 两段程序的输出分别是:
|
||||
|
||||
### **程序1 输出:**
|
||||
|
||||
```
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
0
|
||||
```
|
||||
|
||||
### **程序2 输出:**
|
||||
|
||||
```
|
||||
8
|
||||
1
|
||||
8
|
||||
1
|
||||
8
|
||||
8
|
||||
```
|
||||
57
ObjectOrientedProgramming/OOP/oop_hw5/hw2/animal.cpp
Normal file
57
ObjectOrientedProgramming/OOP/oop_hw5/hw2/animal.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "animal.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
Animal::Animal() {
|
||||
name = "#UNDEFINED";
|
||||
weight = -1;
|
||||
}
|
||||
Animal::Animal(std::string n, int w) {
|
||||
name = n;
|
||||
weight = w;
|
||||
}
|
||||
std::string Animal::show_name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
int Animal::show_weight()
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
void Animal::who() {
|
||||
std::cout << "This is an Animal" << std::endl;
|
||||
std::cout << "Name : " << name << std::endl
|
||||
<< "Weight : " << weight << std::endl;
|
||||
}
|
||||
Lion::Lion() {
|
||||
this->change_name("#UNDEFINED_LION_NAME");
|
||||
this->change_weight(-1);
|
||||
}
|
||||
Lion::Lion(std::string n,int w) {
|
||||
this->change_name(n);
|
||||
this->change_weight(w);
|
||||
}
|
||||
void Lion::who() {
|
||||
std::cout << "This is a Lion" << std::endl;
|
||||
std::cout << "Name : " << this->show_name() << std::endl
|
||||
<< "Weight : " << this->show_weight() << std::endl;
|
||||
}
|
||||
Aardvark::Aardvark() {
|
||||
this->change_name("#UNDEFINED_LION_NAME");
|
||||
this->change_weight(-1);
|
||||
}
|
||||
Aardvark::Aardvark(std::string n, int w) {
|
||||
this->change_name(n);
|
||||
this->change_weight(w);
|
||||
}
|
||||
void Aardvark::who() {
|
||||
std::cout << "This is a Aardvark" << std::endl;
|
||||
std::cout << "Name : " << this->show_name() << std::endl
|
||||
<< "Weight : " << this->show_weight() << std::endl;
|
||||
}
|
||||
void Animal::change_name(std::string cn) {
|
||||
name = cn;
|
||||
}
|
||||
void Animal::change_weight(int cw) {
|
||||
weight = cw;
|
||||
}
|
||||
34
ObjectOrientedProgramming/OOP/oop_hw5/hw2/animal.h
Normal file
34
ObjectOrientedProgramming/OOP/oop_hw5/hw2/animal.h
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
class Animal {
|
||||
private:
|
||||
std::string name;
|
||||
int weight;
|
||||
public:
|
||||
Animal();
|
||||
Animal(std::string n, int w);
|
||||
std::string show_name();
|
||||
int show_weight();
|
||||
void change_name(std::string cn);
|
||||
void change_weight(int cw);
|
||||
virtual void who();
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
class Lion : public Animal {
|
||||
public:
|
||||
Lion();
|
||||
Lion(std::string n, int w);
|
||||
void who();
|
||||
};
|
||||
|
||||
class Aardvark : public Animal {
|
||||
public:
|
||||
Aardvark();
|
||||
Aardvark(std::string n, int w);
|
||||
void who();
|
||||
};
|
||||
17
ObjectOrientedProgramming/OOP/oop_hw5/hw2/main.cpp
Normal file
17
ObjectOrientedProgramming/OOP/oop_hw5/hw2/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include "animal.h"
|
||||
|
||||
using std::cout;
|
||||
using std::cin;
|
||||
using std::endl;
|
||||
|
||||
int main() {
|
||||
Animal a("Animal!", 100);
|
||||
Lion b("Lion W", 200);
|
||||
Aardvark c("Aardvark", 300);
|
||||
a.who();
|
||||
b.who();
|
||||
c.who();
|
||||
return 0;
|
||||
}
|
||||
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw2/测试截图2.png
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw2/测试截图2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 329 KiB |
22
ObjectOrientedProgramming/OOP/oop_hw5/hw3/main.cpp
Normal file
22
ObjectOrientedProgramming/OOP/oop_hw5/hw3/main.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <iostream>
|
||||
#include "person.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
||||
int main() {
|
||||
Employee a[5];
|
||||
Executive b[5];
|
||||
a[0] = Employee(20, "Zhang", 1, 1001);
|
||||
a[1] = Employee(21, "Wang", 1, 1002);
|
||||
a[2] = Employee(19, "Zhao", 0, 1003);
|
||||
a[3] = Employee(22, "Li", 1, 1004);
|
||||
a[4] = Employee(28, "Zh", 0, 1145);
|
||||
a[0].display();
|
||||
a[1].display();
|
||||
a[2].display();
|
||||
a[3].display();
|
||||
a[4].display();
|
||||
return 0;
|
||||
}
|
||||
72
ObjectOrientedProgramming/OOP/oop_hw5/hw3/person.cpp
Normal file
72
ObjectOrientedProgramming/OOP/oop_hw5/hw3/person.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "person.h"
|
||||
|
||||
Person::Person(int a, string n, bool g)
|
||||
{
|
||||
age = a;
|
||||
name = n;
|
||||
gender = g;
|
||||
}
|
||||
|
||||
void Person::change_age(int ca)
|
||||
{
|
||||
age = ca;
|
||||
}
|
||||
|
||||
void Person::change_name(string cn)
|
||||
{
|
||||
name = cn;
|
||||
}
|
||||
|
||||
void Person::change_gender(bool x)
|
||||
{
|
||||
gender = x;
|
||||
}
|
||||
|
||||
int Person::show_age()
|
||||
{
|
||||
return age;
|
||||
}
|
||||
|
||||
string Person::show_name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Person::show_gender()
|
||||
{
|
||||
return gender;
|
||||
}
|
||||
|
||||
void Person::display()
|
||||
{
|
||||
cout << "This is a Person" << endl
|
||||
<< "Name : " << name << endl
|
||||
<< "Age : " << age << endl
|
||||
<< "Gender : ";
|
||||
gender == false ? cout << "Woman" << endl : cout << "Man" << endl;
|
||||
}
|
||||
|
||||
void Employee::add_number(int n)
|
||||
{
|
||||
number = n;
|
||||
}
|
||||
|
||||
void Employee::display()
|
||||
{
|
||||
cout << "This is an Employee" << endl
|
||||
<< "Name : " << this->show_name() << endl
|
||||
<< "Age : " << this->show_age() << endl
|
||||
<< "Gender : ";
|
||||
this->show_gender() == false ? cout << "Woman" << endl : cout << "Man" << endl;
|
||||
cout << "Number ID : " << number << endl;
|
||||
}
|
||||
|
||||
void Executive::display()
|
||||
{
|
||||
cout << "This is an Executive" << endl
|
||||
<< "Name : " << this->show_name() << endl
|
||||
<< "Age : " << this->show_age() << endl
|
||||
<< "Gender : ";
|
||||
this->show_gender() == false ? cout << "Woman" << endl : cout << "Man" << endl;
|
||||
//cout << "Number ID : " << number << endl;
|
||||
}
|
||||
41
ObjectOrientedProgramming/OOP/oop_hw5/hw3/person.h
Normal file
41
ObjectOrientedProgramming/OOP/oop_hw5/hw3/person.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
using std::cout;
|
||||
using std::cin;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
||||
class Person {
|
||||
private:
|
||||
int age;
|
||||
string name;
|
||||
//enum string gender = { "Male","Female" }; <20>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ôд<C3B4><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
bool gender;//1 = Male , 0 = Female
|
||||
public:
|
||||
Person() :age(-1), name("#UNDEFINED"), gender(true) {};
|
||||
Person(int a, string n, bool g);
|
||||
void change_age(int ca);
|
||||
void change_name(string cn);
|
||||
void change_gender(bool x);
|
||||
int show_age();
|
||||
string show_name();
|
||||
bool show_gender();
|
||||
virtual void display();
|
||||
};
|
||||
|
||||
class Employee : public Person {
|
||||
private:
|
||||
int number;
|
||||
public:
|
||||
Employee() :Person(-1, "#UNDEFINED", true), number(-1) {};
|
||||
Employee(int a, string n, bool g, int num) : Person(a, n, g), number(num) {};
|
||||
void add_number(int n);
|
||||
void display();
|
||||
};
|
||||
class Executive : public Employee {
|
||||
public:
|
||||
void display();
|
||||
};
|
||||
|
||||
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw3/测试截图3.png
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw3/测试截图3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 391 KiB |
51
ObjectOrientedProgramming/OOP/oop_hw5/hw4/code/ab.h
Normal file
51
ObjectOrientedProgramming/OOP/oop_hw5/hw4/code/ab.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A(int num) :data1(num) {}
|
||||
~A() {
|
||||
cout << " Destory A" << endl;
|
||||
}
|
||||
void f() const {
|
||||
cout << " Excute A::f() ";
|
||||
cout << " Data1=" << data1 << endl;
|
||||
}
|
||||
void g()
|
||||
{
|
||||
cout << " Excute A::g() " << endl;
|
||||
}
|
||||
protected:
|
||||
int data1;
|
||||
};
|
||||
|
||||
class B : public A
|
||||
{
|
||||
public:
|
||||
B(int num1, int num2) :A(num1), data2(num2) {}
|
||||
~B() {
|
||||
cout << " Destory B" << endl;
|
||||
}
|
||||
void f() const {
|
||||
cout << " Excute B::f() ";
|
||||
cout << " Data1=" << data1;
|
||||
cout << " Data2=" << data2 << endl;
|
||||
}
|
||||
void f(int n) const {
|
||||
cout << " Excute B::f(int) ";
|
||||
cout << " n=" << n;
|
||||
cout << " Data1=" << data1;
|
||||
cout << " Data2=" << data2 << endl;
|
||||
}
|
||||
void h() {
|
||||
cout << " Excute B::h() " << endl;
|
||||
}
|
||||
private:
|
||||
int data2;
|
||||
};
|
||||
72
ObjectOrientedProgramming/OOP/oop_hw5/hw4/code/main.cpp
Normal file
72
ObjectOrientedProgramming/OOP/oop_hw5/hw4/code/main.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A(int num) :data1(num) {}
|
||||
virtual ~A() {
|
||||
cout << " Destory A" << endl;
|
||||
}
|
||||
void f() const {
|
||||
cout << " Excute A::f() ";
|
||||
cout << " Data1=" << data1 << endl;
|
||||
}
|
||||
void g()
|
||||
{
|
||||
cout << " Excute A::g() " << endl;
|
||||
}
|
||||
A& operator=(A& x) {
|
||||
data1 = x.data1;
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
int data1;
|
||||
};
|
||||
|
||||
class B : public A
|
||||
{
|
||||
public:
|
||||
B(int num1, int num2) :A(num1), data2(num2) {}
|
||||
virtual ~B() {
|
||||
cout << " Destory B" << endl;
|
||||
}
|
||||
void f() const {
|
||||
cout << " Excute B::f() ";
|
||||
cout << " Data1=" << data1;
|
||||
cout << " Data2=" << data2 << endl;
|
||||
}
|
||||
void f(int n) const {
|
||||
cout << " Excute B::f(int) ";
|
||||
cout << " n=" << n;
|
||||
cout << " Data1=" << data1;
|
||||
cout << " Data2=" << data2 << endl;
|
||||
}
|
||||
void h() {
|
||||
cout << " Excute B::h() " << endl;
|
||||
}
|
||||
B& operator=(B& x) {
|
||||
data2 = x.data2;
|
||||
//data1 = x.data1;
|
||||
this->A::operator=(x);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
int data2;
|
||||
};
|
||||
|
||||
int main() {
|
||||
B b(1, 2);
|
||||
A* p = new B(1, 2);
|
||||
b.f();
|
||||
b.g();
|
||||
b.f(3);
|
||||
b.h();
|
||||
delete p;
|
||||
return 0;
|
||||
}
|
||||
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw4/测试截图4.png
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw4/测试截图4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 314 KiB |
345
ObjectOrientedProgramming/OOP/oop_hw5/hw4/题目以及答案文字部分.md
Normal file
345
ObjectOrientedProgramming/OOP/oop_hw5/hw4/题目以及答案文字部分.md
Normal file
@@ -0,0 +1,345 @@
|
||||
<!--
|
||||
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
|
||||
* @Date: 2025-05-12 13:19:46
|
||||
* @LastEditors: error: git config user.name & please set dead value or install git
|
||||
* @LastEditTime: 2025-05-12 14:10:25
|
||||
-->
|
||||
## 4.阅读代码,并按要求练习。
|
||||
``` cpp
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A(int num):data1(num) {}
|
||||
~A(){
|
||||
cout<<" Destory A"<<endl;
|
||||
}
|
||||
void f() const{
|
||||
cout<<" Excute A::f() ";
|
||||
cout<<" Data1="<<data1<<endl;
|
||||
}
|
||||
void g()
|
||||
{
|
||||
cout<<" Excute A::g() "<<endl;
|
||||
}
|
||||
private:
|
||||
int data1;
|
||||
};
|
||||
|
||||
class B : public A
|
||||
{
|
||||
public:
|
||||
B(int num1,int num2):A(num1),data2(num2) {}
|
||||
~B(){
|
||||
cout<<" Destory B"<<endl;
|
||||
}
|
||||
void f( ) const{
|
||||
cout<<" Excute B::f() ";
|
||||
cout<<" Data1="<< data1;
|
||||
cout<<" Data2="<<data2<<endl;
|
||||
}
|
||||
void f(int n) const{
|
||||
cout<<" Excute B::f(int) ";
|
||||
cout<<" n="<<n;
|
||||
cout<<" Data1="<< data1;
|
||||
cout<<" Data2="<<data2<<endl;
|
||||
}
|
||||
void h(){
|
||||
cout<<" Excute B::h() "<<endl;
|
||||
}
|
||||
private:
|
||||
int data2;
|
||||
};
|
||||
```
|
||||
|
||||
## 下面是问题
|
||||
- ##### 1)完成 B 类的构造函数,使得参数 num1 对应 data1,num2 对应 data2;
|
||||
|
||||
✅已完成:
|
||||
|
||||
```cpp
|
||||
B(int num1, int num2) : A(num1), data2(num2) {}
|
||||
```
|
||||
|
||||
这正确地将 `num1` 传递给基类 A,`num2` 初始化 `data2`。✅
|
||||
|
||||
---
|
||||
|
||||
- ##### 2)尝试在 main 函数中使用这两个类,编译程序看是否有编译错误?指出错误的原因。
|
||||
|
||||
|
||||
✅已完成:
|
||||
|
||||
```cpp
|
||||
B b(1, 2);
|
||||
b.f();
|
||||
b.g();
|
||||
b.f(3);
|
||||
b.h();
|
||||
```
|
||||
|
||||
若此时 A 中 `data1` 是 `private`,则:
|
||||
|
||||
* ✅ `b.f()`、`b.g()`、`b.f(3)`、`b.h()` 都能编译通过。
|
||||
* ⚠️ 但 `B::f()` 中访问 `data1` 会报错(因为 `B` 不能访问 `A::data1` 的 `private` 成员)。
|
||||
---
|
||||
|
||||
- ##### 3)将基类中的 private 改为 protected,再编译。理解 protected 访问权限,在public 继承方式下的可访问性。
|
||||
|
||||
|
||||
|
||||
✅ 将 A 的成员 `private → protected` 后
|
||||
|
||||
* `B` 就可以访问 `A::data1`。
|
||||
* 所以 `B::f()` 和 `f(int)` 中访问 `data1` 合法。
|
||||
* `protected` 在 `public` 继承下,**对子类可见,对外仍然不可见**。
|
||||
|
||||
---
|
||||
- ##### 4)修改 main 函数,如下所示,看看哪些语句合法?为什么?执行的是基类的实现,还是派生类的实现?
|
||||
``` cpp
|
||||
int main()
|
||||
{
|
||||
B b(1,2);
|
||||
b.f();
|
||||
b.g();
|
||||
b.f(3);
|
||||
b.h();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
✅已完成:
|
||||
|
||||
```cpp
|
||||
int main() {
|
||||
B b(1, 2);
|
||||
b.f(); // ✅ 调用 B::f()
|
||||
b.g(); // ✅ 调用 A::g()
|
||||
b.f(3); // ✅ 调用 B::f(int)
|
||||
b.h(); // ✅ 调用 B::h()
|
||||
}
|
||||
```
|
||||
|
||||
**全部合法**,执行的都是定义在类中的相应成员函数,优先使用派生类的版本。
|
||||
|
||||
---
|
||||
- ##### 5)将继承 A 类的继承方式改为 private,编译能通过吗?再执行 4)中的main 函数,看看哪些语句变得不合法了?为什么?
|
||||
✅ 改为 `private` 继承后:
|
||||
|
||||
```cpp
|
||||
class B : private A
|
||||
```
|
||||
|
||||
现在,`A` 的成员都变成 `B` 的私有成员。
|
||||
|
||||
* `main()` 中 `b.g();` 不合法(`A::g()` 是 `private` 了)
|
||||
* `b.f();` 也不合法,因为 `A::f()` 被隐藏
|
||||
* ❌ **除了 `b.f(3)` 和 `b.h()` 还行,其余都报错**
|
||||
|
||||
---
|
||||
|
||||
- ##### 6)将继承 A 类的继承方式改回 public,并实现 B 类自定义的拷贝构造和赋值函数。
|
||||
|
||||
✅已构造A类的operator+
|
||||
|
||||
```cpp
|
||||
class B : public A {
|
||||
// ...
|
||||
public:
|
||||
B(const B& other) : A(other), data2(other.data2) {}
|
||||
B& operator=(const B& other) {
|
||||
if (this != &other) {
|
||||
A::operator=(other);
|
||||
//或者
|
||||
this->A::operator=(other);
|
||||
//这种写法也可以
|
||||
data2 = other.data2;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
- ##### 7)分别创建 A 和 B 类的两个对象 a 和 b,分别执行 a.f(),b.f(),a.g(),b.g(),a.f(1),b.f(1),a.h(),b.h(),请问哪些可以通过编译,执行结果如何?
|
||||
✅ 调用:
|
||||
|
||||
```cpp
|
||||
A a(1);
|
||||
B b(2, 3);
|
||||
a.f(); // ✅ A::f()
|
||||
b.f(); // ✅ B::f()
|
||||
a.g(); // ✅ A::g()
|
||||
b.g(); // ✅ A::g() 继承而来
|
||||
a.f(1); // ❌ 无此函数
|
||||
b.f(1); // ✅ B::f(int)
|
||||
a.h(); // ❌ 无此函数
|
||||
b.h(); // ✅ B::h()
|
||||
```
|
||||
|
||||
---
|
||||
- ##### 8)增加代码 A * p=new B(1,2);,理解向上类型转换的安全性。
|
||||
✅已完成:
|
||||
```cpp
|
||||
A* p = new B(1, 2);
|
||||
```
|
||||
|
||||
✅ 安全,称为“向上转型”(upcasting),**B 是 A 的子类**。安全的主要原因:
|
||||
“向上类型转换的安全性”是面向对象编程中一个很关键但也容易被忽略的点,尤其在 C++ 中。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 什么是向上类型转换(Upcasting)?
|
||||
|
||||
向上类型转换:**将派生类对象的指针或引用转换为基类类型的指针或引用**。
|
||||
|
||||
比如:
|
||||
|
||||
```cpp
|
||||
class A { };
|
||||
class B : public A { };
|
||||
|
||||
B b;
|
||||
A* pa = &b; // 向上类型转换(Upcasting)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 安全性的本质
|
||||
|
||||
### ✅ **向上转换是安全的、隐式允许的**
|
||||
|
||||
因为:
|
||||
|
||||
* 每个派生类对象**本质上包含一个完整的基类子对象部分**。
|
||||
* 所以把 `B*` 转为 `A*` 是有意义的:`A` 的部分总是存在的。
|
||||
|
||||
> 换句话说,你永远可以“安全地把一个更具体的对象视为一个更抽象的对象”。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 示例
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
void foo() { cout << "A::foo\n"; }
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
void bar() { cout << "B::bar\n"; }
|
||||
};
|
||||
|
||||
int main() {
|
||||
B b;
|
||||
A* pa = &b; // 向上转换,安全
|
||||
|
||||
pa->foo(); // ✅合法,调用 A 的函数
|
||||
// pa->bar(); // ❌错误:A 类型中没有 bar()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❗ 注意事项:类型“退化”
|
||||
|
||||
向上转换后:
|
||||
|
||||
* **只能访问基类中的成员**,即便实际指向的是一个派生类对象;
|
||||
* 若函数是非虚函数,则会“静态绑定”到基类版本;
|
||||
* 若函数是虚函数,则会“动态绑定”到派生类重写版本(见多态);
|
||||
|
||||
---
|
||||
|
||||
## ✅ 与向下转换对比
|
||||
|
||||
| 类型转换方式 | 安全性 | 是否隐式 | 风险 |
|
||||
| --------- | ----- | ---- | ---------------- |
|
||||
| 向上转换(B→A) | ✅ 安全 | ✅ 是 | 无 |
|
||||
| 向下转换(A→B) | ❌ 不安全 | ❌ 否 | 若对象本非 B 类型,结果未定义 |
|
||||
|
||||
|
||||
|
||||
---
|
||||
- ##### 9)在 8)的基础上,执行 p->f(),输出是什么?与 B* p=new B(1,2); p->f();的结果一样吗?
|
||||
✅执行后:
|
||||
|
||||
默认情况下(`f()` 非虚函数):
|
||||
|
||||
```cpp
|
||||
p->f(); // 输出 A::f()
|
||||
```
|
||||
|
||||
若你希望执行的是 `B::f()`,**应将 A 的 `f()` 声明为 `virtual`**。
|
||||
|
||||
---
|
||||
- ##### 10)在 8)的基础上,执行 p->f(1),能通过编译吗?为什么?
|
||||
✅编译?
|
||||
|
||||
```cpp
|
||||
p->f(1); // ❌ 报错:A 类中无 f(int)
|
||||
```
|
||||
|
||||
即使实际对象是 B,编译器只看指针类型(A),而 A 没有 `f(int)`。
|
||||
|
||||
---
|
||||
- ##### 11)在 8)的基础上,执行 p->g()和 p->h(),能行吗?为什么?
|
||||
✅编译?
|
||||
|
||||
```cpp
|
||||
p->f(1); // ❌ 报错:A 类中无 f(int)
|
||||
```
|
||||
|
||||
即使实际对象是 B,编译器只看指针类型(A),而 A 没有 `f(int)`。
|
||||
|
||||
---
|
||||
- ##### 12)在 8)的基础上,执行 delete p;,输出是什么?B 类的析构函数执行了吗?
|
||||
✅输出:
|
||||
|
||||
如果 `A` 的析构函数不是 `virtual`,那么:
|
||||
|
||||
```cpp
|
||||
delete p; // 只会调用 A 的析构函数,❌ 不会调用 B 的析构函数
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
Destory A
|
||||
```
|
||||
|
||||
⚠️ 此时会发生**资源泄漏**,因为 `B` 中资源未释放!
|
||||
|
||||
✅ 正确写法是:
|
||||
|
||||
```cpp
|
||||
class A {
|
||||
public:
|
||||
virtual ~A() {
|
||||
cout << "Destory A" << endl;
|
||||
}
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
这样 `delete p;` 才会调用 B 的析构函数 → 输出顺序:
|
||||
|
||||
```
|
||||
Destory B
|
||||
Destory A
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 总结重点
|
||||
|
||||
| 问题 | 核心知识 |
|
||||
| ---- | -------------------------- |
|
||||
| 2–3 | 访问权限(private vs protected) |
|
||||
| 4–5 | 继承方式(public/private)影响成员访问 |
|
||||
| 6 | 拷贝构造函数 & 赋值操作符 |
|
||||
| 7–11 | 多态、向上转型、成员函数隐藏 |
|
||||
| 12 | 虚析构函数,资源释放 |
|
||||
|
||||
---
|
||||
|
||||
128
ObjectOrientedProgramming/OOP/oop_hw5/hw5/main.cpp
Normal file
128
ObjectOrientedProgramming/OOP/oop_hw5/hw5/main.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
class A {
|
||||
public:
|
||||
A(int num) : data(num) {
|
||||
cout << "A constructed with data = " << data << endl;
|
||||
}
|
||||
void AFuncs() {
|
||||
cout << "This is A's public function!" << endl;
|
||||
}
|
||||
A(const A& other) : data(other.data) {
|
||||
cout << "A copy constructor called." << endl;
|
||||
}
|
||||
A& operator=(const A& other) {
|
||||
if (this != &other) {
|
||||
data = other.data;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~A() {
|
||||
cout << "A destructor called." << endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
int data;
|
||||
};
|
||||
|
||||
class B {
|
||||
public:
|
||||
B(int num) : value(num) {
|
||||
cout << "B constructed with value = " << value << endl;
|
||||
}
|
||||
void BFuncs() {
|
||||
cout << "This is B's public function!" << endl;
|
||||
}
|
||||
B(const B& other) : value(other.value) {
|
||||
cout << "B copy constructor called." << endl;
|
||||
}
|
||||
B& operator=(const B& other) {
|
||||
if (this != &other) {
|
||||
value = other.value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~B() {
|
||||
cout << "B destructor called." << endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
int value;
|
||||
};
|
||||
|
||||
// === ԭʼ<D4AD><CABC><EFBFBD>̳а汾 ===
|
||||
class C1 : public A, private B {
|
||||
public:
|
||||
C1(int num1, int num2, int y) : A(num1), B(num2), yyy(y) {
|
||||
cout << "C1 constructed with yyy = " << yyy << endl;
|
||||
}
|
||||
void MyFuncs() {
|
||||
BFuncs();
|
||||
cout << "This function calls B::BFuncs() !" << endl;
|
||||
}
|
||||
|
||||
private:
|
||||
int yyy;
|
||||
};
|
||||
|
||||
// === <20><><EFBFBD>̳<EFBFBD> + <20><><EFBFBD>ϰ汾 ===
|
||||
class C2 : public A {
|
||||
public:
|
||||
C2(int num1, int num2, int y)
|
||||
: A(num1), b(num2), yyy(y) {
|
||||
cout << "C2 constructed with yyy = " << yyy << endl;
|
||||
}
|
||||
|
||||
C2(const C2& other)
|
||||
: A(other), b(other.b), yyy(other.yyy) {
|
||||
cout << "C2 copy constructor called." << endl;
|
||||
}
|
||||
|
||||
C2& operator=(const C2& other) {
|
||||
if (this != &other) {
|
||||
A::operator=(other);
|
||||
b = other.b;
|
||||
yyy = other.yyy;
|
||||
}
|
||||
cout << "C2 assignment operator called." << endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~C2() {
|
||||
cout << "C2 destructor called." << endl;
|
||||
}
|
||||
|
||||
void MyFuncs() {
|
||||
b.BFuncs();
|
||||
cout << "This function calls B::BFuncs() !" << endl;
|
||||
}
|
||||
|
||||
private:
|
||||
B b;
|
||||
int yyy;
|
||||
};
|
||||
|
||||
// === <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
|
||||
int main() {
|
||||
cout << "=== <20><><EFBFBD>̳в<CCB3><D0B2><EFBFBD> ===" << endl;
|
||||
C1 obj1(10, 20, 30);
|
||||
obj1.AFuncs();
|
||||
obj1.MyFuncs();
|
||||
cout << endl;
|
||||
|
||||
cout << "=== <20><><EFBFBD>̳<EFBFBD> + <20><><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD> ===" << endl;
|
||||
C2 obj2(100, 200, 300);
|
||||
obj2.AFuncs();
|
||||
obj2.MyFuncs();
|
||||
|
||||
cout << "--- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---" << endl;
|
||||
C2 obj3 = obj2;
|
||||
|
||||
cout << "--- <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD> ---" << endl;
|
||||
C2 obj4(1, 2, 3);
|
||||
obj4 = obj3;
|
||||
|
||||
cout << "--- <20><><EFBFBD><EFBFBD>˳<EFBFBD><CBB3><EFBFBD><EFBFBD>ʼ ---" << endl;
|
||||
return 0;
|
||||
}
|
||||
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw5/测试截图5.png
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw5/测试截图5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 356 KiB |
131
ObjectOrientedProgramming/OOP/oop_hw5/hw6/main.cpp
Normal file
131
ObjectOrientedProgramming/OOP/oop_hw5/hw6/main.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
||||
class Wall
|
||||
{
|
||||
public:
|
||||
Wall() :color(0)
|
||||
{
|
||||
cout << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ǽ" << endl;
|
||||
}
|
||||
void Paint(int newColor)
|
||||
{
|
||||
color = newColor;
|
||||
cout << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD>ˢǽ" << endl;
|
||||
}
|
||||
int GetColor() const
|
||||
{
|
||||
return color;
|
||||
}
|
||||
virtual void display() {
|
||||
cout << "ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ0<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD>5<EFBFBD><EFBFBD>6<EFBFBD><EFBFBD>7<EFBFBD><EFBFBD><EFBFBD><EFBFBD>8" << endl;
|
||||
cout << "Wall Color ? : " << this->GetColor() << endl;
|
||||
|
||||
}
|
||||
virtual ~Wall() {
|
||||
cout << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Wall" << endl;
|
||||
}
|
||||
private:
|
||||
int color;
|
||||
};
|
||||
class Door
|
||||
{
|
||||
public:
|
||||
Door() :openOrClose(false)
|
||||
{
|
||||
cout << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << endl;
|
||||
}
|
||||
void Open()
|
||||
{
|
||||
if (!IsOpened())
|
||||
{
|
||||
openOrClose = true;
|
||||
cout << "<EFBFBD>ű<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "<EFBFBD>ſ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD>" << endl;
|
||||
}
|
||||
}
|
||||
void Close()
|
||||
{
|
||||
if (IsOpened())
|
||||
{
|
||||
openOrClose = false;
|
||||
cout << "<EFBFBD>ű<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD>" << endl;
|
||||
}
|
||||
}
|
||||
bool IsOpened() const
|
||||
{
|
||||
return openOrClose;
|
||||
}
|
||||
virtual ~Door() {
|
||||
|
||||
}
|
||||
private:
|
||||
bool openOrClose;
|
||||
};
|
||||
//<2F><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>ɫ0<C9AB><30>1<EFBFBD><31>2<EFBFBD><32>3<EFBFBD><33>4<EFBFBD><34>5<EFBFBD><35>6<EFBFBD><36>7<EFBFBD><37><EFBFBD><EFBFBD>8
|
||||
class WallWithDoor : public Wall, public Door{
|
||||
public:
|
||||
WallWithDoor() : Door(), Wall(){}
|
||||
WallWithDoor(bool fl,int cl) {
|
||||
this->Paint(cl);
|
||||
fl == true ? this->Open() : this->Close();
|
||||
if (cl == 1) this->Close();
|
||||
if (cl == 4) this->Open();
|
||||
}
|
||||
void display() {
|
||||
cout << "ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ0<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD>5<EFBFBD><EFBFBD>6<EFBFBD><EFBFBD>7<EFBFBD><EFBFBD><EFBFBD><EFBFBD>8" << endl;
|
||||
cout << "Door is Open? :" << this->IsOpened() << endl;
|
||||
cout << "Wall Color ? : " << this->GetColor() << endl;
|
||||
}
|
||||
};
|
||||
|
||||
class WallWithDoor_Combined {
|
||||
private:
|
||||
Door x;
|
||||
Wall y;
|
||||
public:
|
||||
WallWithDoor_Combined() : x(), y() {}
|
||||
WallWithDoor_Combined(bool fl, int cl) {
|
||||
y.Paint(cl);
|
||||
fl == true ? x.Open() : x.Close();
|
||||
if (cl == 1) x.Close();
|
||||
if (cl == 4) x.Open();
|
||||
}
|
||||
void display() {
|
||||
cout << "ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ0<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD>5<EFBFBD><EFBFBD>6<EFBFBD><EFBFBD>7<EFBFBD><EFBFBD><EFBFBD><EFBFBD>8" << endl;
|
||||
cout << "Door is Open? :" << x.IsOpened() << endl;
|
||||
cout << "Wall Color ? : " << y.GetColor() << endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
WallWithDoor a1(true,1);
|
||||
WallWithDoor a2(true, 2);
|
||||
WallWithDoor a3(true, 4);
|
||||
WallWithDoor_Combined b1(true,1);
|
||||
WallWithDoor_Combined b2(true, 2);
|
||||
WallWithDoor_Combined b3(true, 4);
|
||||
Wall* p = new Wall();
|
||||
Wall* t1 = &a1; //<2F><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
WallWithDoor* t2 = dynamic_cast<WallWithDoor*> (p);//<2F><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
cout << typeid(t2).name() << endl;
|
||||
p->display();
|
||||
a1.display();
|
||||
a2.display();
|
||||
a3.display();
|
||||
b1.display();
|
||||
b2.display();
|
||||
b3.display();
|
||||
return 0;
|
||||
}
|
||||
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw6/测试截图6.png
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/hw6/测试截图6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 437 KiB |
BIN
ObjectOrientedProgramming/OOP/oop_hw5/上机测试5 (1).pdf
Normal file
BIN
ObjectOrientedProgramming/OOP/oop_hw5/上机测试5 (1).pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user