C/C++:02 1/2. 类和对象

文章目录

  • 前言
  • 1. 类的定义和对象的创建
    • 类的定义
    • 创建对象
    • 访问类成员
    • 使用对象指针
  • 2. 类的成员变量和成员函数
    • 成员函数的定义:
      • 类体和类外定义成员函数的区别
  • 3. C++类成员的访问权限以及类的封装
    • 成员的访问限定
    • 类的封装
  • 6. C++构造函数
    • 构造函数的重载
    • 默认构造函数
  • 7. 构造函数初始化列表
  • 8. 析构函数
    • 析构函数的执行时机
  • 9. 对象数组
  • 10. 成员对象和封闭类
    • 成员对象初始化
    • 成员对象的消亡
  • 结论


前言


1. 类的定义和对象的创建

类的定义

类通常定义在函数的外面;

class Student{
public:
	//成员变量
	char* name;
	int age;
	float score;
	//成员函数
	void say()
	{
		std::cout<<"hello.\n"<

注意类定义最后有一个分号;,它是类定义的一部分,表示类定义结束了,不能省略。

类只是一个模板(Template),编译后不占内存空间,所以在定义类时不能队成员变量进行初始化,因为没有地方存储数据。只有在创建对象以后才会给成员变量分配内存,这个时候就可以赋值了。

创建对象

Student liLei;			// 创建对象
class Student LiLei 	// 创建对象
Student allStu[100]; 	// 创建对象数组

访问类成员

可以通过 dot(.) 方式访问类成员

    Student stu;
    stu.name = "小明";
    stu.age = 15;
    stu.score = 92.5f;
    stu.say();

使用对象指针

  • 定义栈对象
Student stu;
Student *pStu = &stu;
  • 定义堆对象
Student *pStu = new Student;
pStu -> name = "小明";
pStu -> age = 15;
pStu -> score = 92.5f;
pStu -> say();

在堆上分配内存,没有名字,只能通过一个指针指向;堆内存由程序员管理,对象使用完毕之后可以通过delete来删除。

2. 类的成员变量和成员函数

类的成员函数和普通函数区别:成员函数是一个类的成员,出现在类体中,它的作用范围由类来决定;而普通函数是独立的,作用范围是全局的。

成员函数的定义:

  • 类体中定义
    类体中定义成员函数时,不需要在函数名前面加上类名。
  • 类外定义
    成员函数定义在类外时,必须在函数名前面加上类名予以限定。::被称为域解析符(也称作用域运算符或作用域限定符)
    成员函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前

类体和类外定义成员函数的区别

  • 类体中定义的成员函数会自动称为内联函数(也可以手动添加inline关键字,但是是多余的),类外定义的不会。
  • 内联一般不是我们期望看到的,它会将函数调用处函数体替代,所以建议在类体内部对函数声明,在类体外部进行定义
  • 如果想定义内联函数,直接定义在类内部即可。

3. C++类成员的访问权限以及类的封装

成员的访问限定

限定符 类中访问限制 类外访问限制
public 可以相互访问 可通过对象访问
protected 可以相互访问 不可访问
private 可以相互访问 不可访问

成员访问限定符只能对类的成员进行修饰,不能修饰类,C++中的类没有共有私有之分。

类的封装

  • 根据C++软件设计规范,成员变量和类内部使用的成员函数都建议声明为private
  • 如果成员变量和成员函数 没有被声明private或者public,默认为private

6. C++构造函数

构造函数是一种特殊的成员函数,它的名字和类名相同,却没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象的时候自动执行。
如下代码:

#include 
using namespace std;

class Student{
private:
	char* m_name;
	int m_age;
	float m_score;
public:
	//声明构造函数
	Student(char* name, int age, float score);
	//声明普通函数
	void display();
};

//定义构造函数
Student::Student(char* name, int age, float score){
	m_name = name;
	m_age = age;
	m_score = score;
}

void Student::display(){
	cout<< m_name << "的年龄是"<< m_age<<", 成绩是" << m_score<<endl;
}

int main()
{
	//创建对象时向构造函数传递参数
	Student stu("何小", 15, 92.5f);
	stu.display();

	//创建对象时向构造函数传参
	Student *pstu = new Student("小花", 16, 98);
	pstu->display();

	return 0;
}

构造函数的重载

构造函数可以重载,一个类可以有多个重载的构造函数,创建对象时根据传递的实参来判断调用哪个构造函数。

构造函数的调用是强制性的,一旦在类中定义了构造函数,创建对象的时候一定要调用。如果有多个重载的构造函数,那么创建对象时提供的实参必须和其中的一个构造函数匹配;

默认构造函数

如果用户没有自定义构造函数,编译器会自动生成一个默认的构造函数,只是这个构造函数体是空的,没有形参,也不执行任何操作:

Student(){}

调用没有参数的构造函数也可以省略括号:Student stu() == Student stu

7. 构造函数初始化列表

构造函数最重要的任务便是 对成员变量进行初始化。

class Student{
private:
	const char* name;
	int age;
	float score;
};
  • 采用列表初始化
Student::Student(char* name, int age, float score):m_name(name),m_age(age),m_score(score){
	//TODO
}
  • 赋值初始化
Student::Student(char* name, int age, float score):m_name(name){
	m_age = age;
	m_score = score;
}

const 修饰的变量只能通过 初始化列表赋值,表示不可修改。
成员变量初始化顺序与初始化列表中列出的变量顺序无关,只与成员变量在类中的声明顺序有关

8. 析构函数

与构造函数相对立的就是析构函数,用来释放分配的内存、关闭打开的文件等。
析构函数(Destruction)也是一种特殊的成员函数,没有返回值,不需要程序员显示调用(程序员也没法显式调用),而是在销毁对象的时候自动执行

Student(int len);  // 构造函数
~Student(); 	   // 析构函数
#include 
using namespace std;

class VLA{
public:
	VLA(int len);		//构造函数
	~VLA();				//析构函数
};

VLA::VLA(int len):m_len(len){
	if(len > 0)
		m_arr = new int[len];	//分配内存
	else
		m_arr = null;
}

VLA::~VLA(){
	delete[] m_arr; 	//释放内存
}

析构函数的执行时机

  • 所有函数之外创建的对象都是全局对象,它和全局变量类似,位于内存分区中的全局数据区,程序在结束的时候会调用这些对象的析构函数。
  • 在函数内部创建的对象时局部对象,它和局部变量类似,位于栈区,函数执行结束时会调用这些对象的析构函数。
  • new创建的对象位于堆区,通过delete删除时才会调用析构函数;如果没有delete,析构函数就不会被执行。

9. 对象数组

在构造函数有多个参数时,数组的初始化列表中要显式包含对构造函数的调用,例如:

class CTest{
public:
	CTest(int n){}  //构造函数(1)
	CTest(int n, int m){} 	//构造函数(2)
	CTest(){}			//构造函数(3)
};
int main(){
	// 三个元素分别用构造函数(1)(2)(3)初始化
	CTest array1[3] = {1, CTest(1, 2)};
	// 三个元素分别用构造函数(2)(2)(1)初始化
	CTest array2[3] = {CTest(2, 3), CTest(1, 2), 1};
	//两个元素指向的对象分别用构造函数(1)(2)初始化
	CTest* pArray[3] = {new CTest(4), new CTest(1,2)};
	
	return 0;
}

10. 成员对象和封闭类

一个类的成员如果是另一个类的对象,就称之为“成员对象”。包含成员对象的类叫封闭类(enclosed class)

成员对象初始化

#include 
using namespace std;

// 轮胎类
class Tyre{
private:
    int m_width;
    int m_radius;
public:
    Tyre(int width, int radius);
    void display();
};
Tyre::Tyre(int width, int radius):m_width(width), m_radius(radius){}
void Tyre::display(){
    cout<< "tyre width is"<< m_width <<"\n" << "tyre radius is" << m_radius<<endl;
}
// 引擎类
class Engine{
private:
    float m_displacement;
public:
    Engine(float displacement = 12.0);
    void display();
};
Engine::Engine(float displacement):m_displacement(displacement){}
void Engine::display(){
    cout<< "引擎大小为"<<m_displacement<<"\n"<<endl;
}

// 汽车类
class Car{
private:
    float m_price;
public:
    Tyre my_tyre;
    Engine my_engine;
public:
    Car(int width, int radius, float price);
    void display();
};

// 指明m_tyre对象的初始化方式*/{ };
Car::Car(int width, int radius, float price):my_tyre(width, radius){
    m_price = price;
}
void Car::display(){
    cout << "价格:" << this->m_price << "¥" << endl;
    this->my_tyre.display();
    this->my_engine.display();
}

int main(int argc, char** argv){
    Car car(200, 300, 500000);
    car.display();

    return 0;
}

在上面的程序中,如果 Car 类的构造函数没有初始化列表,那么第 51 行就会编译出错,因为编译器不知道该如何初始化 car.m_tyre 对象,因为 Tyre 类没有无参构造函数,而编译器又找不到用来初始化 car.m_tyre 对象的参数。

成员对象的消亡

封闭类对象生成时,先执行所有成员对象的构造函数,然后执行封闭类自己的构造函数。成员对象构造函数的执行次序和成员对象在类定义中的次序一致,与他们在构造函数初始化列表中出现的次序无关。

当封闭类对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数,成员对象析构函数的执行次序和构造函数的执行次序相反,即先构造的后析构。

#include 
using namespace std;

class Typr{
public:
    Typr(){cout<< "typr constru" <<endl;}
    ~Typr(){cout<< "typr destru" <<endl;}
};

class Engine{
public:
    Engine(){cout<< "Engine constru" <<endl;}
    ~Engine(){cout<< "Engine destru" <<endl;}
};

class Car{
private:
    Typr m_typr;
    Engine m_engine;
public:
    Car(){cout<< "Car constru" <<endl;}
    ~Car(){cout<< "Car destru" <<endl;}
};

int main()
{
    Car *car = new Car;
    delete car;

    return 0;
}

运行结果

typr constru
Engine constru
Car constru
Car destru
Engine destru
typr destru

结论

你可能感兴趣的:(C/C++基础,c++,c语言)