1) C++ 中类的三大特性是什么?请简要解释。
类的对象:属性(成员变量)行为(成员方法/函数)
类的定义:
class 类名{
权限:
成员变量,
成员方法,
};
三大特性:继承性,封装性,多态性
继承性 继承允许一个类继承另一个类的属性和方法
继承允许创建一个新的类(派生类或子类)从一个已有的类(基类或父类)派生出来。派生类继承
了基类的所有非 private(私有)成员变量和成员函数(构造函数和析构函数除外),并且可以添
加自己的新成员或者重写基类的成员函数。这就好比子女会继承父母的一些特征,同时也有自己的
个性。
例如下面这个基类Vehicle,它有成员变量speed和成员函数drive(),然后有一个派生类Car继承自
Vehicle,Car类就自动拥有了speed变量和drive()函数避免了代码的重复编写,通过重写drive方
法,所以会输出 “汽车可以驾驶”,而不是Vehicle类中drive函数的车辆可以驾驶。
class Vehicle {
public:
int speed;
void drive()
{
cout << "车辆可以驾驶" << endl;
}
};
class Car :public Vehicle {
public:
void drive()
{
cout << "汽车可以驾驶" << endl;
}
};
int main()
{
Car car;
car.speed = 75;
car.drive();//汽车可以驾驶
return 0;
}
封装性 将数据和操作封装在类中(将属性和行为看作一个整体,表现事物)),通过访问修饰符控制
访问权限
常见的访问修饰符有:
public://公有权限:可以类内(成员方法)访问,子类访问,对象访问(通过.访问)
protected://受保护权限:可以类内(成员方法)访问,子类访问
private://私有权限:只能类内(成员方法)访问
例如下面这个银行账户类, 它是由属性(账户余额)和行为(存款,取款)构成了独立的单元,来体现
银行账户这个事物
class BankAccount {
private:
int balance;//账户余额
public:
void deposit()
{
cout << "存款" << endl;
}
void withdraw()
{
cout << "取款" << endl;
}
};
int main()
{
BankAccount account;
//account.balance = 5000;//报错:不能修改私有成员变量的值,保证了数据的安全性
account.deposit();//public成员函数可以在外部访问
}
多态性 多态是通过基类指针或引用调用派生类的函数实现不同的行为
多态主要通过虚函数来实现。当有一个基类指针或引用指向派生类对象时,通过这个指针或引用调
用虚函数,实际调用的是派生类中重写后的虚函数,这是在运行时根据对象的实际类型来决定的
#include <iostream>
using namespace std;
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound." << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Dog barks." << endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Cat meows." << endl;
}
};
int main()
{
Dog dog;
dog.makeSound();//Dog barks.
return 0;
}
2)什么是构造函数和析构函数?它们的作用是什么?
构造函数:
作用:1.构造函数是给成员变量赋值
对象角度:初始化类对象 ;成员变量角度:对成员变量赋值
定义:2.构造函数和类名相同,没有返回值,不写void
类名()
{
函数体
}
3.构造函数在创建对象时,编译器自动帮我们调用无需手动调用
4.如果没有实现构造函数,编译器会提供默认的构造函数,不过函数体为空
类名()
{
}
5.构造函数有参数,可以进行重载或者给参数默认值
6.如果我们实现了有参构造,编译器就不会提供默认的无参构造
7.构造函数可以是私有的,但是是在单例模式下。
调用构造函数的三种方式:1.括号法 2.显示法 3.隐式转换法
class point{
int* p;
public:
point()
{
cout << "调用无参构造函数" << endl;
}
point(int n)
{
cout << "调用有参数的构造函数" << endl;
if (n > 0)
{
p = new int(10);
}
else
{
p = NULL;
cout << "数据不准确" << endl;
}
}
void print()
{
if (p) cout <<"打印p指向堆区内存的值" <<* p << endl;
}
};
int main()
{
point p1;//调用无参构造
p1.print();//输出"调用无参构造函数"
point p2(-3);//输出 "调用有参数的构造函数","数据不准确"
p2.print();
point t(1); //括号法
point t1 = point(3);//显示法
point t2 = 3;//隐式转换法
point t3();//不是括号法调用无参构造,会被编译器识别为函数的声明
return 0;
}
析构函数
析构函数的主要功能:释放指针变量指向的堆区内存
定义:
定义:~类名()
{
函数体
}
1.无参数,不能重载
2.没有返回值,不用写void
3.程序销毁对象时自动调用,不用手动调用,且只调用一次
4.名字和类名相同且前面有~
5.没有实现析构函数时,编译器提供默认的析构函数
6.析构函数是释放指针成员变量所指向的堆区内存
7.类外声明,类内实现。
class A {
int* p;
public:
A() {
p = NULL;
}
A(int n) {
p = new int[n];
}
~A(){
if (p) delete []p;
}
};
int main()
{
A* a = new A(3);//先在堆区申请A类型的对象,给构造函数传参参数为3,a在栈区,栈区a指向堆区1的对象,堆区中有指针成员变量p,p指向一块堆区2内存
//new:先调用malloc开辟堆区内存1,再走构造函数给开辟的这块堆区内存1赋值,
delete a;//先调用析构函数p释放堆区内存2,在调用free释放堆区内存1
cout << "well" << endl;
return 0;
}