45gfg9
本帖最后由 45gfg9 于 2020-8-31 17:01 编辑


索引贴
答案帖


Prev: C++Ⅴ:类与对象
Next: C++Ⅶ:继承 & 多态


2021.12 数据,可能有更多内容


索引贴
答案帖

Prev: C++Ⅴ:类与对象
Next: C++Ⅶ:继承 & 多态



1 为类创建单独文件


1.1 创建新类


一般地,在单独的文件里定义你要用的新类是好习惯。这会让维护和阅读代码更简单。
要这样做的话,在CodeBlocks中这样做:
点击File->New->Class...
给你的新类起个名,取消选择"Has destructor"并选择"Header and implementation file shall be in same folder",然后点击"Create"按钮。



注意到有两个新文件已经添加到你的项目了:

新文件就是我们新类的模板。MyClass.h文件。MyClass.cpp文件。

Part题:
通常,哪两个文件定义一个类?
A. 头文件和主文件
B. 类文件和源文件
C. 头文件和源文件
D. 头文件和体文件


1.2 源文件 & 头文件(一)


头文件 (.h) 包含了函数声明(原型)和变量声明。
它现在包含我们新的MyClass类的模板,有一个默认构造函数。
MyClass.h
```cpp
#ifndef MYCLASS_H
#define MYCLASS_H


class MyClass
{
public:
    MyClass();
protected:
private:
};


#endif // MYCLASS_H
```
类的实现和方法体放在源文件 (.cpp) 中。
目前它只包括一个空的构造函数。
MyClass.cpp
```cpp
#include "MyClass.h"


MyClass::MyClass()
{
   //ctor
}
```
头文件中的#ifndef和#define语句接下来的课程讲。

Part题:
头文件作用是?
A. 函数原型和变量声明
B. 只有构造函数
C. 函数源码
D. 什么都没有


1.3 作用域解析运算符


源文件 (.cpp) 中的双冒号叫做作用域解析运算符Scope Resolution Operator,在构造函数的定义中有用到:
```cpp
#include "MyClass.h"


MyClass::MyClass()
{
   //ctor
}
```
作用域解析运算符用来定义一个特定的类的已经声明了的成员函数。记住,我们在头文件中定义构造函数原型。
所以基本上讲,MyClass::MyClass()指的是MyClass()成员函数——或者在本例中,MyClass类的构造函数。

Part题:
用选项填空,创建一个属于demo类的函数test。
```cpp
______ :: ______ ()
{
}
```
`test  class  make  function  demo`


1.4 源文件 & 头文件(二)


要在main中使用我们的类的话,我们需要包含头文件


举例,如果在main中用我们新创建的MyClass
```cpp
#include <iostream>
#include "MyClass.h"
using namespace std;


int main() {
MyClass obj;
}
```
头文件声明了类(或者不管实现的是什么)会"做什么",而cpp源文件定义了它"如何做"。

Part题:
要使用类,main.cpp中要包含什么?
A. 类的源文件
B. 源文件和头文件都要
C. 类的头文件



2 析构函数


2.1 析构函数(一)


还记得构造函数么?它们是当对象被创建时调用的特殊成员函数。
析构函数Destructors也是特殊函数。它们会在当对象被销毁删除时调用。
对象在离开定义域时会被销毁,或者将delete表达式应用到指向这个类对象的指针时会被删除。

Part题:
下面关于C++中构造函数和析构函数的表述中,哪条正确?
A. 构造函数在对象被创建时调用;析构函数当其被删除时调用
B. 构造函数在当对象被删除时调用
C. 析构函数在当对象被创建时调用


2.2 析构函数(二)


析构函数的名字也与类名一致,只是有一个波浪号 (~)前缀。析构函数不能返回值,也不能有参数。
```cpp
class MyClass {
public:
    ~MyClass() {
  // some code
    }
};
```
析构函数在程序中释放资源时非常有用。这可以包括关闭文件、释放内存等等。

Part题:
什么是析构函数符号?


2.3 析构函数(三)


举个例子,我们来给我们的MyClass类声明一个析构函数,在MyClass.h头文件中:
```cpp
class MyClass
{
public:
   MyClass();
   ~MyClass();
};
```
这个我们的MyClass类声明了一个析构函数。

Part题:
用选项填空,给MyClass类声明一个析构函数。
```cpp
class MyClass {
public:
MyClass();
______;
};
```
`~MyClass()  destructor()  !MyClass()  MyClass~~`


2.4 析构函数(四)


在头文件中声明析构函数之后,我们可以在源文件MyClass.cpp中写实现了:
```cpp
#include "MyClass.h"
#include <iostream>
using namespace std;


MyClass::MyClass()
{
cout<<"Constructor"<<endl;
}


MyClass::~MyClass()
{
cout<<"Destructor"<<endl;
}
```
注意到我们使用了<iostream>头文件,以来使用cout


Part题:
用选项填空,给类MyClass声明一个析构函数,其向屏幕输出文字。
```cpp
MyClass:: ______ {
______ ______ "some text";
}
```
`>>  cout  ~MyClass()  <<  destructor`


2.5 析构函数(五)


因为析构函数不能有参数,所以其不能被重载。
每个类只会有一个析构函数。
析构函数不是必须的;如果不需要用就可以不用定义。

Part题:
下面的表述哪些正确?
A. 析构函数不能重载
B. 析构函数永远返回double
C. 析构函数不能有任何参数
D. 析构函数无名称


2.6 析构函数(六)


回到main吧。
```cpp
#include <iostream>
#include "MyClass.h"
using namespace std;


int main() {
MyClass obj;


return 0;
}
```
我们包含了类的头文件并创建了那个类型的对象。这会有如下输出:
```
Constructor
Destructor
```
程序运行时,它先创建一个对象并调用构造函数。程序执行完成后,对象被销毁,析构函数被调用。
我们在构造函数中输出了"Constructor",在析构函数中输出了"Destructor"。

Part题:
析构函数...
A. ...在对象被删除时调用
B. ...在构造函数没有被调用时调用
C. ...是成员变量



3 箭头成员运算符


3.1 #ifndef & #define


我们给我们的类创建了单独的头文件和源文件,头文件如下:
```cpp
#ifndef MYCLASS_H
#define MYCLASS_H


class MyClass
{
public:
MyClass();
protected:
private:
};


#endif // MYCLASS_H
```
ifndef意味如果没有被定义if not defined。第一对语句告诉程序,如果还未定义MyClass头文件,就定义它。
endif结束这个条件。
这会防止同一个头文件被包含超过一次。

Part题:
#ifndef和#define语句的意图是什么?
A. 让程序跑得更快
B. 防止同一头文件在一个文件内被包含多于一次
C. 是std命名空间的需要


3.2 成员函数


我们来给类创建一个示例函数myPrint()
MyClass.h
```cpp
class MyClass
{
public:
   MyClass();
   void myPrint();
};
```
MyClass.cpp
```cpp
#include "MyClass.h"
#include <iostream>
using namespace std;


MyClass::MyClass() {
}


void MyClass::myPrint() {
cout <<"Hello"<<endl;
}
```
因为myPrint()是普通成员函数,所以在声明和定义中都必须标注其返回类型

Part题:
用选项填空,在Sally类中创建myPrint函数原型。
```cpp
______ Sally {
______ :
Sally();
void ______ ();
};
```
`public  myPrint  function  class  prototype`


3.3 点运算符


接着来创建一个MyClass类型的对象,然后用点 (.) 运算符调用其myPrint()函数:
```cpp
#include "MyClass.h"


int main() {
MyClass obj;
obj.myPrint();
}


// 输出 "Hello"
```


Part题:
用选项填空,声明一个Sally类对象,并用点 (.) 运算符调用其myPrint成员函数。
```cpp
int main() {
______ obj;
______ . ______;
}
```
`class  obj  myPrint()  dot  Sally`


3.4 指针(四)


我们也可以用指针访问对象成员。
下面的指针指向obj对象。
```cpp
MyClass obj;
MyClass *ptr = &obj;
```
指针类型是MyClass,其指向那个类型的对象。

Part题:
填空声明一个指向obj的指针:
```cpp
Sally obj;
Sally _ sallyPtr = _ obj;
```


3.5 箭头成员运算符


箭头成员选择运算符arrow member selection operator用于用指针访问对象成员。
```cpp
MyClass obj;
MyClass *ptr = &obj;
ptr->myPrint();
```
当使用对象时,用成员选择运算符 (.)。
当使用指向对象的指针时,使用箭头成员选择运算符 (->)。

Part题:
填上缺失的箭头运算符来通过sallyPtr调用myPrint()函数。
```cpp
Sally obj;
Sally *sallyObj = &obj;
sallyPtr __ myPrint();
```





4 常量对象


4.1 常量


常量是有固定值的表达式。在程序运行时,它不能被改变。
const关键字定义常量。
```cpp
const int x = 42;
```
任何常量都必须在创建时初始化。

Part题:
填空声明double类型的常量var。
```cpp
_____ double ___ = 3.4;
```


4.2 常量对象(一)


如内置类型一样,我们也可以用const关键字创建常量对象。
```cpp
const MyClass obj;
```
所有的const变量都必须在创建时初始化。对类而言,初始化由构造函数完成。如果函数不是用带参构造函数创建的,那么必须提供一个公有默认构造函数——如果没有提供公有默认构造函数,则会产生编译错误。


当const对象通过构造函数创建时,你不能修改对象的成员变量。这既包括对public成员变量的修改,也包括通过成员函数修改成员变量。
当你用const声明对象时,在对象生命期内无法改变其数据成员。

Part题:
用选项填空,声明一个Student类型的对象st,并调用其printAge()函数。
```cpp
______ st;
st. ______;
```
`~Student  class  st  Student  printAge()`


4.3 常量对象(二)


只有非const对象才能调用非const函数。
一个常量对象无法调用普通函数。因此,要使用常量对象,必须需要一个常量函数。


要声明一个函数为const成员,函数原型的右圆括号后,必须跟const关键字。对于那些在类定义外定义的const成员函数,const关键字必须在函数原型和定义中都要有。举例:
MyClass.h
```cpp
MyClass.h
class MyClass
{
public:
    void myPrint() const;
};
```
MyClass.cpp
```cpp
#include "MyClass.h"
#include <iostream>
using namespace std;


void MyClass::myPrint() const {
cout <<"Hello"<<endl;
}
```
现在myPrint()函数是一个常成员函数了。既然如此,我们的常量对象可以调用它了:
```cpp
int main() {
const MyClass obj;
obj.myPrint();
}
// 输出 "Hello"
```


Part题:
填上缺失的关键字,为Student类声明一个常成员函数printAge()。
```cpp
_____ Student {
public:
void printAge() _____ ;
};
```


4.4 常量对象(三)


尝试在常量对象内调用普通函数会产生错误。
另外,当任何const成员函数尝试改变成员变量或调用非const成员函数时产生编译错误。
定义常量对象和常函数确保对应的数据成员不会被意外修改。

Part题:
常成员函数...
A. ...不能被调用
B. ...能修改非const数据成员
C. ...不能修改任何非const数据成员



5 成员初始化


5.1 成员初始化(一)


回忆一下,常量是值无法改变的变量,所有const变量都必须在创建时初始化。


C++提供了一种顺手的语法用来初始化类成员,叫做成员初始化列表member initializer list(也叫构造函数初始化器constructor initializer)。


Part题:
常量...
A. ...必须不被初始化
B. ...不能被改变
C. ...能被修改


5.2 成员初始化(二)


考虑下面的类:
```cpp
class MyClass {
public:
   MyClass(int a, int b) {
    regVar = a;
    constVar = b;
   }
private:
    int regVar;
    const int constVar;
};
```
此类有两个成员变量,regVarconstVar。它也有一个构造函数接受两个参数,用于初始化成员变量。
运行此代码会产生错误,因为它其中的一个成员变量是常量,不能在声明后改变值。


在这种例子中,成员初始化列表能用来给成员变量赋值。
```cpp
class MyClass {
public:
MyClass(int a, int b)
: regVar(a), constVar(b)
{
}
private:
int regVar;
const int constVar;
};
```
注意到上面语法,初始化列表跟着构造函数形参。列表由冒号 (:) 开始,接着列出了要初始化的变量和要赋的值,以逗号分隔。
用语法变量(值)赋值。
初始化列表消除了在构造函数体内显式赋值的必要。而且,初始化列表不需以分号结束。

Part题:
你有一个类Student,有两个成员age和num。填空用对应的值在构造函数初始化器中初始化成员。
```cpp
Student::Student(int a, int b)
_ age(a),
    ___ (b) {
}
```


5.3 成员初始化(三)


让我们用独立头文件和源文件重写前例。
MyClass.h
```cpp
class MyClass {
public:
   MyClass(int a, int b);
private:
   int regVar;
   const int constVar;
};
```
MyClass.cpp
```cpp
MyClass::MyClass(int a, int b)
: regVar(a), constVar(b)
{
cout << regVar << endl;
cout << constVar << endl;
}
```
我们在构造函数中添加了cout语句来输出成员变量的值。
下一步就是在main创建一个我们类的对象,并用构造函数赋值。
```cpp
#include "MyClass.h"


int main() {
MyClass obj(42, 33);
}


/*输出
42
33
*/
```
构造函数用于创建对象,通过成员初始化列表用形参给成员变量赋值。

Part题:
用选项填空,在构造函数初始化列表中初始化成员,然后在构造函数体内输出。
```cpp
Student:: ______ (int a, int b)
: regVar(a),
    constVar(b)
{cout << ______ <<
constVar ______ endl;
}
```
`regVar  ::  <<  >>  Student`


5.4 成员初始化(四)


成员初始化列表可以用在普通变量上,必须用在常量上。
即使成员变量不是常量,用成员初始化语法也很有用。

Part题:
常成员变量...
A. ...必须在构造函数体内初始化
B. ...必须在构造函数初始化列表中初始化
C. ...怎么初始化随你



6 组合(第一部分)


6.1 组合(一)


在现实生活中,复杂对象基本是用更小更简单的对象建造的。举例,一辆车用金属框架、引擎、轮胎,和大量其他部件组装。这个过程叫组合composition


在C++中,对象组合是通过将类作为其他类的成员而完成的。
这个示例程序演示了组合的使用。它包含PersonBirthday类,每个Person都会有一个Birthday对象作为其成员。
Birthday:
```cpp
class Birthday {
public:
Birthday(int m, int d, int y)
: month(m), day(d), year(y)
{
}
private:
   int month;
   int day;
   int year;
};
```
我们的Birthday类有三个成员变量。它也有通过成员初始化列表初始化成员的构造函数。
为了简洁,这个类在单文件中声明。你也可以分开源文件和头文件。

Part题:
填空在构造函数初始化列表中初始化Birthday类成员。
```cpp
Birthday::Birthday(int m, int d, int y)
_ month(m),
day(d),
year( _ )
{
}
```


6.2 组合(二)


让我们给Birthday类也加一个printDate()函数。
```cpp
class Birthday {
public:
Birthday(int m, int d, int y)
: month(m), day(d), year(y)
{
}
void printDate()
{
   cout<<month<<"/"<<day
   <<"/"<<year<<endl;
}
private:
int month;
int day;
int year;
};
```
这给我们的Birthday类添加了printDate()函数。

Part题:
用选项填空,创建类People,有三个私有整型成员:birthMonth,birthDay,birthYear。
```cpp
class ______ {
public:
People();
______
int ______ ;
int birthDay;
______ birthYear;
};
```
`public  People  private:  int  birthMonth  var`


6.3 组合(三)


接着,我们可以创建Person类了,其包含Birthday类。
```cpp
#include <string>
#include "Birthday.h"


class Person {
public:
Person(string n, Birthday b)
: name(n),
   bd(b)
{
}
private:
string name;
Birthday bd;
};
```
Person类有nameBirthday成员,和一个初始化它们的构造函数。
确保包含了对应的头文件。
下一节继续讲组合

Part题:
用选项填空,声明People类,有两个私有成员:类型string的name和类型Birthday的dateOfBirth。别忘记包含string类型的头文件和Birthday.h。
```cpp
#include < ______ >
#include " ______ "
class ______ {
public:
People(string n, Birthday bo);
private:
string name;
______ dateOfBirth;
};
```
`Birthday.h  Birthday  People  string`



7 组合(第二部分)


7.1 组合(四)


现在,我们的Person类有Birthday类的成员了:
```cpp
class Person {
public:
Person(string n, Birthday b)
: name(n),
    bd(b)
{
}
private:
string name;
Birthday bd;
};
```
组合常被用在有包含关系的对象上,如“Person生日Birthday”。

Part题:
填空声明People的构造函数,接受两个参数并初始化其私有成员:name和dateOfBirth。
```cpp
People::People(string x, Birthday bo)
_ name( _ ), dateOfBirth(bo)
{
}
```


7.2 组合(五)


让我们来给Person类添加一个printInfo()函数,输出对象的数据:
```cpp
class Person {
public:
Person(string n, Birthday b)
: name(n),
bd(b)
{
}
void printInfo()
{
   cout << name << endl;
   bd.printDate();
}
private:
string name;
Birthday bd;
};
```
注意到我们可以调用成员bdprintDate()函数,因为它是Birthday类型,且定义了那个函数。

Part题:
用选项填空,定义printInfo()函数,输出“人”的"People's"姓名name生日birthdate,用dateOfBirth的printDate()函数。
```cpp
void People:: ______ () {
cout << name << endl;
______ . ______ ();
}
```
`printDate  const  printInfo  dateOfBirth  class`


7.3 组合(六)


现在我们有了Birthday类和Person类,可以去main,创建一个Birthday对象,并传给Person对象了。
```cpp
int main() {
Birthday bd(2, 21, 1985);
Person p("David", bd);
p.printInfo();
}


/*输出
David
2/21/1985
*/
```
我们创建了Birthday对象,代表日期1985年2月21日。接着,我们创建了一个Person对象,并将Birthday对象传给其构造函数。最终,我们用Person对象的printInfo()函数输出其数据。
一般来说,组合旨在将每个类保持得相对简单明了,只执行一项任务。这也允许每个子对象变得自包含,确保了重用性(我们可在其他类中使用Birthday类)。

Part题:
用选项填空,声明一个People类型的对象,其接受一个字符串作为第一个参数,一个Birthday对象作为第二个参数。在传递给People构造函数前,声明一个Birthday对象birthObj。
```cpp
______ birthObj(10, 30, 1989);
People john("John", ______ );
```
`birthObj  Birthday  string  class  People`



8 friend关键字


8.1 友元函数(一)


通常,一个类的私有成员不能被其外界访问。
然而,声明一个非成员函数为类的友元friend允许它访问这个类的私有成员。这是通过在类中包含一个这个外部函数的声明,并用friend关键字放在声明前来达成的。
下例中,someFunc(),不是类的成员函数,是MyClass的友元,可以访问其私有成员。
```cpp
class MyClass {
public:
MyClass() {
   regVar = 0;
}
private:
int regVar;


friend void someFunc(MyClass &obj);
};
```
注意到我们给函数传递对象时,我们需要用&运算符通过引用传递

Part题:
什么是声明友元的关键字?


8.2 友元函数(二)


someFunc()函数在类外以正常函数的方式定义。它接受一个MyClass类型的对象作为其形参,并有权访问那个对象的私有数据成员。
```cpp
class MyClass {
public:
MyClass() {
   regVar = 0;
}
private:
int regVar;


friend void someFunc(MyClass &obj);
};


void someFunc(MyClass &obj) {
obj.regVar = 42;
cout << obj.regVar;
}
```
someFunc()函数改变了对象的私有成员并输出其值。
要使其对象可访问,类需要在其定义内将函数声明为友元。如果类没有“将访问权限给出”,你就不能“使”这个函数成为类的友元。

Part题:
填上缺失的关键字,使函数foo成为MyClass类的友元。
```cpp
class MyClass {
public:
______ void foo();
};
```


8.3 友元函数(三)


现在我们可以在main中创建对象并调用someFunc()函数了。
```cpp
int main() {
MyClass obj;
someFunc(obj);
}


//输出 42
```
someFunc()有权修改对象的私有成员并输出其值。


友元函数的典型用例是可能涉及访问两个不同类的私有成员的函数。
你可以在任意数量的类中声明一个函数是其友元
与友元函数类似,你可以定义友元类,其有权限访问另一个类的私有成员。

Part题:
友元函数...
A. ...只能修改公有成员
B. ...不能修改类的私有成员
C. ...可以修改包括私有成员在内的类的所有成员



9 this关键字


9.1 this(一)


C++中每个对象都可访问自己的地址,通过一种重要的指针,叫做this指针。
在成员函数中,this可以用来指代调用对象。
我们来创建一个示例类。
```cpp
class MyClass {
public:
MyClass(int a) : var(a)
{ }
private:
int var;
};
```
友元函数没有this指针,因为友元不是类的成员。

Part题:
用选项填空,声明一个Hannah类,有一个一参构造函数,一个printCrap()函数,和一个私有整型变量。
```cpp
class Hannah {
_____ :
Hannah(int);
void printCrap();
private:
______ h;
};
```
`int  private  public  friend  class`


9.2 this(二)


printInfo()方法提供了三种输出类的成员变量的方式。
```cpp
class MyClass {
public:
MyClass(int a) : var(a)
{ }
void printInfo() {
   cout << var<<endl;
   cout << this->var<<endl;
   cout << (*this).var<<endl;
}
private:
int var;
};
```
三种方式输出相同。
this是一个指向对象的指针,所以箭头选择符用于选择成员变量。

Part题:
对于一个名为mem的成员,选择两项可以正确输出它的方式。
A. cout << this->mem;
B. cout << this>>mem;
C. cout << mem;
D. cout ** mem;


9.3 this(三)


要看到结果,我们可以创建一个我们类的对象并调用成员函数。
```cpp
#include <iostream>
using namespace std;


class MyClass {
public:
MyClass(int a) : var(a)
{ }
void printInfo() {
   cout << var <<endl;
   cout << this->var <<endl;
   cout << (*this).var <<endl;
}
private:
int var;
};


int main() {
MyClass obj(42);
obj.printInfo();
}


/* 输出
42
42
42
*/
```
所有三种访问成员变量的方式都有效。
注意到只有成员函数有this指针。

Part题:
什么是存储当前对象地址的关键字?


9.4 this(四)


你也许在想可以直接指定变量时,为什么要用this关键字。


this关键字在运算符重载operator overloading中有举足轻重的地位,接着我们会讲到。


Part题:
对于类MyClass,有一个私有成员名为mem,填空在printValue()函数中通过this关键字输出其值。
```cpp
void MyClass::printValue() {
cout << ____ -> ___;
}
```





10 运算符重载


10.1 运算符重载(一)


C++中大多运算符都可以被重定义或重载
因此,用户定义的类型也可以使用各种运算符(例如你可以将两个对象相加)。


下表列出可以重载的运算符。

不能重载的运算符包括 :: | .* | . | ?:

Part题:
用选项填空,声明类Sally,公有范围内只有构造函数。
```cpp
______ Sally
{
______ :
______ ();
};
```
`~Sally  private  public  Sally  class`


10.2 运算符重载(二)


让我们声明一个示例类,用于演示运算符重载:
```cpp
class MyClass {
public:
int var;
MyClass() {}
MyClass(int a)
: var(a) { }
};
```
我们的类有两个构造函数和一个成员变量。
我们会重载+运算符,允许我们相加两个我们的类对象。

Part题:
填空声明类Sally,有两个构造函数,一个是默认构造函数(无参),另一个有一个整型参数。
```cpp
_____ Sally
{
______ :
Sally();
Sally( ___ );
};
```


10.3 运算符重载(三)


重载的运算符是函数,由关键字operator后跟要重载运算符的符号定义。
被重载的运算符与其他函数类似,有返回类型形参列表


在我们的例子中,我们会重载+运算符。它会返回一个我们类的对象并接受一个我们类的对象作为其形参
```cpp
class MyClass {
public:
int var;
MyClass() {}
MyClass(int a)
: var(a) { }


MyClass operator+(MyClass &obj) {
}
};
```
现在,我们要定义函数的行为。

Part题:
哪个选项是在C++中重载运算符的关键字?
A. operator
B. this
C. overload_it
D. friend


10.4 运算符重载(四)


我们需要我们的+运算符返回一个新的MyClass对象,其成员变量等于两个对象成员变量之和。
```cpp
class MyClass {
public:
int var;
MyClass() {}
MyClass(int a)
: var(a) { }


MyClass operator+(MyClass &obj) {
   MyClass res;
   res.var= this->var+obj.var;
   return res;
}
};
```
在这,我们声明了一个新res对象。之后我们将当前对象(this)和形参对象(obj)的成员变量之和赋给res对象的成员变量var。res对象作为结果返回。


这给我们在main中创建对象并用被重载的+运算符相加对象的能力。
```cpp
int main() {
MyClass obj1(12), obj2(55);
MyClass res = obj1+obj2;


cout << res.var;
}


//输出 67
```
有了重载运算符,你可以使用任何需要的自定义逻辑了。然而,无法改变运算符优先级、组合或操作数数量。

Part题:
用选项填空,定义Test类的被重载的+运算符。
```cpp
Test Test:: ______ (Test obj) {
______ newObj;
newObj.mem =
    mem ______ obj.mem;
return newObj;
}
```
`Test  class  +  operator+  const`

本章测试


1. 填空声明Student类的析构函数。
```cpp
class Student {
public:
Student();
_ Student();
};
```


2. 填空声明指向st的指针,st类型是Student,之后通过指针调用printAge()。
```cpp
Student st;
Student _ stPtr = _ st;
stPtr __ printAge();
```


3. 填上缺失的关键字,声明一个Person类型的常量对象:
```cpp
_____ Person obj;
```


4. 对于类P,其有一个double型常成员weight,填空在构造函数初始化列表中初始化weight。
```cpp
P::P(double w) _
______ (w)
{
}
```


5. 什么是允许你指定一个函数是类的友元函数的关键字?
A. this
B. friendly
C. friend
D. make_friend


6. 对于类Test,其有两个私有成员名为mem和mem2,填空在printValues()函数内使用this关键字输出其值。
```cpp
void Test::printValues() {
cout << ____ -> ___;
cout << this __ mem2;
}
```


7. C++中重载运算符的关键字是?


langyo


还以为你这个是索引

没想到是零散的东西

以及你可以细致讲一讲五三法则

langyo
本帖最后由 langyo 于 2020-3-28 16:52 编辑

仔细看了下,你还缺了一堆东西

- =default 和 =delete 去哪里了?
- 拷贝构造函数需要更细致的讲解,配合五三讲比较好……
- 模板类有考虑讲不?
- 友元 operator 何时入手?

45gfg9
langyo 发表于 2020-3-28 16:51
仔细看了下,你还缺了一堆东西

- =default 和 =delete 去哪里了?

1. 2. 原文没有 我溜了
我觉得=default和=delete是进阶特性了awa
而且是C++11加的 而这篇教程大概还在用C++98(那咋办嘛)

3. 有(在C++Ⅷ了,不知道什么时候更新233)

4. 友元operator没得 以读者的水平应该可以自己写(逃)

⚡️👮
百万贴大佬

花茶果之城
这个帖子值得纪念,是一个有意义的教程帖子。

Hueihuea
本帖最后由 Hueihuea 于 2020-3-28 22:53 编辑

咦 TID100W拍照留念

咦 挨卡了XD

屑弟弟楚儿
大草
(本来以为至少是在茶馆出现的  教学贴爆冷门)
(反手给我打了一个大嘴巴子)

1784234383
本帖最后由 1784234383 于 2020-3-30 16:19 编辑

还带章末测试 lz有心了

FireworkPolymer
虽然没看懂,但是C++在java版我的世界中有什么用吗(基岩版倒是C++开发的)

BiggayJN
淦,百万帖不发锭不过这也是个不错的教程

45gfg9
FireworkDLC 发表于 2020-3-29 07:40
虽然没看懂,但是C++在java版我的世界中有什么用吗(基岩版倒是C++开发的)

一般来说没有(捂脸)

这个系列与Minecraft无关,就是纯粹的编程入门

FireworkPolymer
45gfg9 发表于 2020-3-29 09:15
一般来说没有(捂脸)

这个系列与Minecraft无关,就是纯粹的编程入门

所以“我的世界”中文论坛为什么要开这个板块

Salt_lovely
话说C++会不会有一天可以用于Java版的插件开发?(好像不太可能,跨平台就要重新编译了吧)

洞穴夜莺
FireworkDLC 发表于 2020-3-29 07:40
虽然没看懂,但是C++在java版我的世界中有什么用吗(基岩版倒是C++开发的)

有用,写启动器

FloatingBlocks
这个
只学到函数的我瑟瑟发抖

感觉我那本书太详细了堪比手册

这个知识密度太高了,改天当手册用吧

支持lz(还是百万帖子恭喜了

冷枫小乐
恭喜成为100w贴,雾,好评

88453877
我就是来水个帖子的

剑眉狼
百万贴,恭喜恭喜
纯干货嗷,先收藏为敬了

丶追忆
哇。没抢到锭,真难受

nidb
C艹乃秃头源泉

遗忘的流髑
百万帖恭喜!

一只小水怪
100w贴!!!

AzureZeng
就是你抢了TID1000000? 原来是存草稿了,我们还以为被删了

hjxhjx2
本帖最后由 hjxhjx2 于 2020-4-4 14:55 编辑

谔谔C++OIer表示我不管这块
我只会算法QAQ(红黑树什么的)
只有2,4,5,8,9,10部分是我熟悉的。。。
(关于class。。。struct不香吗。。。class在OI中很废的...)
话说friend是不是可以用const代替来着啊。。。。
lz不打算另外出个帖子讲一下吗

馄饨=w=
dalao,百万,考古

[编辑于2080-1-1:]一亿前来考古

45gfg9
hjxhjx2 发表于 2020-4-4 14:54
谔谔C++OIer表示我不管这块
我只会算法QAQ(红黑树什么的)
只有2,4,5,8,9,10部分是我熟悉的。。。

算法我完全痴呆(

friend和const是完全不同的两个东西啊

以及如果有需要的话 可能未来(大概)会开一个答疑帖吧

hjxhjx2
45gfg9 发表于 2020-4-5 23:01
算法我完全痴呆(

friend和const是完全不同的两个东西啊

但是我用STL重载运算符时似乎必须要加个friend或者const(??)
(好吧我对于一些语法并不了解。。。)

屈子墨
看完这个后 我竟不知道是先学java还是c++了

池恩TwT
1000000 留念

小凡Eric
百万考古留恋

Garyjel
自编2048
#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
using namespace std;
long long a[1001][1001],s,h,n,pl;
int ct(int i,int j)
{
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),8);
        cout<<"║ ";
        if(a[i][j]==0) cout<<"  ";
        if(a[i][j]==1)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED |FOREGROUND_GREEN | FOREGROUND_BLUE);
                cout<<"□";
        }
        if(a[i][j]==2)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),3);
                cout<<"□";
        }
        if(a[i][j]==4)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
                cout<<"□";
        }
        if(a[i][j]==8)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN |FOREGROUND_BLUE);
                cout<<"□";
        }
        if(a[i][j]==16)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED |FOREGROUND_GREEN);
                cout<<"□";
        }
        if(a[i][j]==32)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
                cout<<"■";
        }
        if(a[i][j]==64)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),3);
                cout<<"■";
        }
        if(a[i][j]==128)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
                cout<<"■";
        }
        if(a[i][j]==256)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN |FOREGROUND_BLUE);
                cout<<"■";
        }
        if(a[i][j]==512)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED |FOREGROUND_GREEN);
                cout<<"■";
        }
        if(a[i][j]==1024)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
                cout<<"○";
        }
        if(a[i][j]==2048)
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
                cout<<"◎";
        }
}
int f(int x)
{
        if(x==119)//up
        {
                for(int j=1;j<=n;j++)
                        for(int i=1;i<=n;i++)
                        {
                                int xl=i;
                                while(a[xl-1][j]==0&&xl>1)
                                {
                                        a[xl-1][j]=a[xl][j];
                                        a[xl][j]=0;
                                        xl--;
                                }
                                if(a[xl-1][j]==a[xl][j])
                                {
                                        a[xl][j]=0;
                                        a[xl-1][j]*=2;
                                }
                        }
        }
        if(x==115)//down
        {
                for(int j=1;j<=n;j++)
                        for(int i=n;i>=1;i--)
                        {
                                int xl=i;
                                while(a[xl+1][j]==0&&xl<n)
                                {
                                        a[xl+1][j]=a[xl][j];
                                        a[xl][j]=0;
                                        xl++;
                                }
                                if(a[xl+1][j]==a[xl][j])
                                {
                                        a[xl][j]=0;
                                        a[xl+1][j]*=2;
                                }
                        }
        }
        if(x==97)//left zuo
        {
                for(int i=1;i<=n;i++)
                        for(int j=1;j<=n;j++)
                        {
                                int yl=j;
                                while(a[i][yl-1]==0&&yl>1)
                                {
                                        a[i][yl-1]=a[i][yl];
                                        a[i][yl]=0;
                                        yl--;
                                }
                                if(a[i][yl-1]==a[i][yl])
                                {
                                        a[i][yl]=0;
                                        a[i][yl-1]*=2;
                                }
                        }
        }
        if(x==100)//right you
        {
                for(int i=1;i<=n;i++)
                        for(int j=n;j>=1;j--)
                        {
                                int yl=j;
                                while(a[i][yl+1]==0&&yl<n)
                                {
                                        a[i][yl+1]=a[i][yl];
                                        a[i][yl]=0;
                                        yl++;
                                }
                                if(a[i][yl+1]==a[i][yl])
                                {
                                        a[i][yl]=0;
                                        a[i][yl+1]*=2;
                                }
                        }
        }
}
int main()
{
        n=4;
        while(s<n*n)
        {
                s=0; h=0;
                int xl,s1=0,zl=1;
                for(int i=1;i<=n;i++)
                        for(int j=1;j<=n;j++)
                                if(!a[i][j]) s1++;
                                else h+=a[i][j];
                if(s1==0)
                {
                        cout<<"GAME OVER --------"<<h;
                        return 0;
                }
                srand(time(0));
                xl=rand();
                zl=rand();
                zl%=2; xl%=s1;
                zl++; xl++;
                for(int i=1;i<=n;i++)
                        if(xl)
                        {
                                for(int j=1;j<=n;j++)
                                        if(!a[i][j])
                                        {
                                                if(xl==1)
                                                {
                                                        a[i][j]=zl;
                                                }
                                                xl--;
                                        }
                        }
                        else break;
                system("cls");
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),8);
                cout<<"╔";
                for(int i=1;i<=n-1;i++) cout<<" ═ ╦";
                cout<<" ═ ╗"<<endl;
                for(int i=1;i<=n-1;i++)
                {
                        for(int j=1;j<=n;j++)
                        {
                                ct(i,j);
                        }
                        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),8);
                        cout<<"║"<<endl<<"╠";
                        for(int i=1;i<=n-1;i++) cout<<" ═ ╬";
                        cout<<" ═ ╣"<<endl;
                }
                for(int j=1;j<=n;j++)
                {
                        ct(n,j);
                }
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),8);
                cout<<"║";
                cout<<endl<<"╚";
                for(int i=1;i<=n-1;i++) cout<<" ═ ╩";
                cout<<" ═ ╝";
                int z=getch();
                f(z);
        }
        cout<<"GAME OVER --------"<<h;
        return 0;
}

bilegole
#在这里快速回复#        百万留名 你火了

dingbohao
2020年8月8日前来考古

kayn-
感谢大佬翻译和转载