Q:类中可以包含几种类型的成员?它们是什么?
A:类的成员可分为private(私有的)、public(公有的)和protected(受保护的)三种类型。
private:此关键字后面声明的时类的私有类型成员。私有数据成员和成员函数是不透明的,它们只允许本类的成员函数来访问,不能在类的定义域之外被访问。
public:此关键字后面声明的是类的公有类型成员,它们是类与外部的接口,外界可以通过这些接口与类发生联系。
protected:此关键字后面声明的是类的保护类型成员,它们用于类的继承和派生,它们不能被类外直接访问,允许本类的成员函数或派生类的成员函数来访问。
Q:请描述构造函数和析构函数的功能和特点,如何定义构造函数和析构函数?
A:c++中的类是一种数据类型,为了使用户自定义类的使用和一般数据类型的使用一样,需要建立一种方法,使对象在被创建时进行初始化,在使用结束时进行撤销。构造函数就是为此设计的。
构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,在创建对象时自动执行。构造函数的功能是由用户定义,用户根据初始化要求设计函数体和函数参数。
构造函数具有如下特点:
1)构造函数的名字必须与类名相同,编译系统以此识别并将它作为构造函数处理;
2)构造函数一般声明为public,无返回值,因此无需定义返回类型;
3)构造函数是系统自动调用的,且只能执行一次;
析构函数也是一个特殊的成员函数,它的命名是在类名前面加一个“”符号。在c++中,””是按位取反运算符,由此可知。析构函数是与构造函数作用相反的函数。析构函数具有如下特点:
1)析构函数与类名相同,并要在前面加“~”符号;
2)析构函数不能接收任何参数,也没有返回类型说明;
3)一个类只有一个析构函数。
当对象的生命期结束时,会自动执行析构函数。如果出现以下几种情况,程序会执行析构函数:
1)如果在一个函数中定义了一个对象(它是自动局部对象),当这个函数结束时,对象应该释放,在对象释放前自动执行析构函数;
2)如果定义了一个全局对象,则在程序的流程离开作用域时(如main函数结束或调用exit函数)时,将调用该全局对象的析构函数;
3)如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,将先调用该对象的析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。
析构函数是逆序执行的。
Q:定义一个日期类Date,该类存放一个日期,要求实现以下功能:
1)void GetDate();//取日期值,格式如“2010年5月10日”
2)SetDate(int year,int month,int day);//设置日期值
A:
#include <iostream>
using namespace std;
class Date{
private:
int year0;
int month0;
int day0;
public:
Date(int year,int month,int day){
this->year0=year;
this->month0=month;
this->day0=day;
}
void DateShow(){
cout<<year0<<"年"<<month0<<"月"<<day0<<"日"<<endl;
}
void DateSet(int y,int m,int d){
this->year0=y;
this->month0=m;
this->day0=d;
}
~Date(){
cout<<"清理成功"<<endl;
}
};
int main(){
Date d1(2021,2,3);
d1.DateShow();
d1.DateSet(1010,1,0);
d1.DateShow();
return 0;
}
Q:创建一个Student类,该类中具有学生姓名、学号、性别、年龄、成绩等数据成员。在该类中定义成员函数实现相关信息的输出以及学生成绩的统计(求平均成绩),将函数的原型声明放在类定义中,用构造函数初始化每个成员,要求显示信息函数将对象中的完整信息打印出来,并要求将数据成员定义为保护(private)方式。
A:
#include<iostream>
#include<string>
using namespace std;
class Student
{
static double sum; //定义总成绩变量为静态数据
private:
string name,sex,number;
int year;
double result;
public:
Student(); //构造函数
~Student(){
cout<<"清理成功"<<endl;
}; //析构函数
void input(); //信息输入函数
void display(); //信息输出函数
void mean(int y); //求平均成绩函数
};
Student::Student()
{
name="no mane";
sex="no";
number="0";
year=0;
result=0;
}
void Student::mean(int y)
{
cout<<endl<<"所有人的平均成绩是:"<<sum/y<<endl;
}
void Student::input()
{
cout<<"姓名:";
cin>>name;
cout<<"性别:";
cin>>sex;
cout<<"学号:";
cin>>number;
cout<<"年龄:";
cin>>year;
cout<<"成绩:";
cin>>result;
}
void Student::display()
{
cout<<"姓名:"<<name<<" 性别:"<<sex<<" 学号:"<<number<<" 年龄:"<<year<<" 成绩:"<<result<<endl;
sum+=result; //计算总成绩
}
double Student::sum=0; //初始化总成绩为0
int main()
{
int i,j;
char judge='0';
Student *a=new Student[100];//使用new动态分配数组个数
Student b; //创建b对象
cout<<"请输入所有人的信息:"<<endl;
for(i=0;judge!='n';i++)
{
cout<<i+1<<"号 ";
a[i].input();
cout<<"是否结束输入(按n键结束,按其他键继续):";
cin>>judge;
}
cout<<endl<<"所有人的信息是:"<<endl;
for(j=0;j<i;j++)
a[j].display();
b.mean(i);
return 0;
}
Q:什么是引用,如何定义引用,引用和指针有何区别,c++使用引用的好处有哪些?
A:
1)所谓引用就是一个别名,变量的引用就是变量的别名,因此引用又称为别名;
2)如果想给变量a起一个别名b,可以这样些:
int a;int &b=a;以上语句声明了b是a的引用,即b是a的别名。此后,a或b的作用相同,都代表同一变量。其中&是引用声明符,并不代表地址。将b声明为a的引用,不需要为b另外开辟内存单元。b和a占用内存中同一个存储单元,它们具有同一地址;
3)引用是受限的指针,参考c++引用与指针的区别
4)引用提供的好处表现在函数之间传递和返回参数上。将变量的引用作为函数参数来传递,提供了传递地址同样的功能但舍弃了其复杂的语法。
Q:什么是友元,友元的作用是什么?
A:为了解决在类的外部访问类的私有成员和保护成员,通过公有成员函数访问效率低的问题,提出了友元机制。友元关系有三种,即友元可以是类外定义的普通函数(友元函数),也可以是类定义的成员函数(友元成员),还可以是类外定义的某一个类(友元类);
1)友元声明可以放在类的私有部分,也可以放在类的公有部分;
2)友元关系不具有传递性
3)友元关系不具有交换性
Q:什么是重载,函数重载有哪些表现形式,运算符重载有哪几种实现方式?
A:
1)重载,是指“同一标识符”在同一作用域的不同场合具有不同的语义,这个标识符可以实函数名或者运算符,也就是说,重载可以使多个函数使用同一个函数名,或者同一个运算符代表不同的运算规则。因此,重载包括函数重载和运算符重载,c++使用重载是为了使程序简洁;
2)函数重载,c++允许用同一函数名定义多个函数,这些函数的参数个数和参数类型不同,这就是函数重载。
#include <iostream>
using namespace std;
class Show{
public:
void print(char);//声明一个带字符参数的成员函数
void print(char*);//声明一个带字符串指针的成员函数
void print(int,char);//声明一个带整型、字符参数的成员函数
};
void Show::print(char cc){
int i;
for(i=0;i<25;i++){
cout<<cc;
}
cout<<endl;
}
void Show::print(char *str){
cout<<str<<endl;
}
void Show::print(int number,char character){
for(int i=0;i<number;i++){
cout<<character;
}
cout<<endl;
}
int main(){
Show c1,c2,c3;
char *str="hello c++";
c1.print('#');
c2.print(str);
c3.print(25,'*');
return 0;
}
3)运算符重载是对已有的运算符赋予多重含义,使得同一运算符作用于不同类型的数据而得到不同类型结果。c++预定义的运算符的操作对象只能是基本的数据类型,重载运算符使得程序员可以把c++运算符的操作对象扩展刀用户自定义的数据类型的情况。
注意:
1.不能重载的运算符:
"."成员访问运算符,
sizeof类型大小运算符
".*"成员指针运算符
?:三目运算符
::作用域运算符
2.重载不能改变运算符操作数的个数
3.重载不能改变运算符的优先级和结合性
4.重载运算符的函数不能有默认参数,否则会改变运算符参数的个数
5.经重载的运算符,其操作数中至少应该有一个是自定义类型
6用于类对象的运算符一般必须重载,但有两个例外,运算符=,因为赋值运算符可用于每一个对象,可以用它在同类对象之间赋值,地址运算符&,也不必重载,它能返回类对象在内存中的起始地址;
7.运算符重载是对原有运算符功能的加强和改造;一般来说,重载之后的功能应该类似于该运算符作用于标准类型数据所实现的功能,以增加程序的可读性和易维护性。
运算符重载的形式:
c++中的运算重载是通过函数调用的形式实现的,实际上就是函数重载。运算符重载有两种形式,即重载为类的友元函数和重载为类的成员函数。
重载运算符“+”使其实现复数相加,要求用友元函数实现:
#include <iostream>
using namespace std;
class Complex{
private:
double real;
double imag;
public:
Complex(){
real=0;
imag=0;
}//重载函数
Complex(double r,double i){
real=r;
imag=i;
}//重载函数参数不同
void display();
friend Complex operator +(Complex c1,Complex c2);//重载函数Complex作为Complex类的友元
};
void Complex::display(){
cout<<real<<","<<imag<<"i"<<","<<endl;
}
Complex operator +(Complex c1,Complex c2){ //定义作为友元的重载函数
return Complex(c1.real+c2.real,c1.imag+c2.imag) ;
}
int main(){
Complex c1(3,4),c2(5,-10),c3;
c3=c1+c2;
cout<<"c1=";c1.display();
cout<<"c2=";c2.display();
cout<<"c1+c2=";c3.display();
return 0;
}
重载运算符“+”,使之能用于两个复数相加,要求用成员函数实现:
#include <iostream>
using namespace std;
class Complex{
private:
double real;
double imag;
public:
Complex(double r,double i);
Complex();
void display();
Complex operator+(Complex c1);
};
Complex::Complex(double r,double i):real(r),imag(i){
};
Complex::Complex():real(0),imag(0){
};
Complex Complex::operator +(Complex c1){
return Complex(c1.real+real,c1.imag+imag);
}
void Complex::display(){
cout<<real<<","<<imag<<"i"<<endl;
}
int main(){
Complex c1(3,4),c2(4,-5),c3;
c3=c1+c2;
cout<<"c3=";c3.display();
return 0;
}
参数表中的参数数目是重载运算符的操作数减一。运算时左操作数是当前对象本身的数据,参数表中的操作数为右操作数。
可参考C++ 运算符重载
Q:编写一个程序,通过执行结果的分析来检验在引用类对象时是否执行了类的构造函数和析构函数?
A:
#include<iostream>
using namespace std;
class test{
private:
string temp;
public:
test();
~test();
void set(string i);
void display();
};
test::test(){
cout<<"执行构造函数!"<<endl;
}
test::~test(){
cout<<"执行析构函数!"<<endl;
}
void test::set(string i){
temp= i;
}
void test::display(){
cout<<temp<<endl;
}
void Quote(){
test source;
source.set("Yes");
test &qt = source;
qt.display();
cout<<"引用完成"<<endl;
}
int main(){
Quote();
system("pause");
return 0;
}
使用引用对象时,不执行构造函数和析构函数。
Q:派生类有哪几种继承方式,对于不同的继承方式,基类中各类成员在派生类中的访问属性如何?
A:
1)派生类只有一个基类的继承关系称为单继承,派生类有两个及以上基类的继承关系称为多继承。
2)继承方式包括三种:public(公有继承)、private(私有继承)和protected(保护继承),这三种继承方式的关键字有且只能有一个,默认继承方式为private。
在已经声明了一个类person的基础上,再建立一个派生类student。
在这里插入代码片
参考资料:
https://blog.csdn.net/weixin_41042404/article/details/86717934
https://blog.csdn.net/qq_27278957/article/details/85269245