C++ 学习(11)类和对象、封装、访问权限、成员属性私有性、构造函数与析构函数

2023-10-27

面向对象的特点:封装、继承、多态。万事万物皆为对象,对象上有其属性和行为(方法)。

1、封装

将属性与行为作为一个整体,表现生活中的事物

将属性和行为加以权限控制(public、private等)

C++封装

语法:

class 类名{

访问权限:

        属性(变量)列表

        行为(方法)列表

}

#include <iostream>
using namespace std;
#define PI 3.14

//类 - 圆
class Circle
{
	//访问权限
public:
	//属性
	//半径
	int radius;

	//方法
	//计算周长
	double circumference()
	{
		return 2 * PI * radius;
	}

	//计算面积
	double area()
	{
		return (PI * radius) * (PI * radius);
	}
};

int main()
{
	//类和对象
	//创建对象:通过一个类创建一个对象的过程,即实例化
	Circle c1;
	//给对象属性赋值
	c1.radius = 2;

	//调用对象方法
	cout << "半径为 " << c1.radius << " 时,圆周长 = " << c1.circumference() << ", 圆面积 = " << c1.area() << endl;

	system("pause");

	return 0;
}

输出结果

半径为 2 时,圆周长 = 12.56, 圆面积 = 39.4384

Go语言封装 

Go语言中没有class关键字,即没有类这个概念,可以通过函数方法表达类的概念,通过函数方法指定某个结构体来实现类。

语法:

func (变量名 结构体名)函数方法名(参数列表) 返回值列表 {

        函数体

}

//结构体名可以是结构体值类型,也可以是结构体指针类型

package main

import "fmt"

const PI = 3.14

//结构体 - 圆
type Circle struct {
	//半径
	radius int
}

//结构体方法
//计算周长
func (c *Circle) circumference() float64 {
	return 2 * PI * float64(c.radius)
}

//计算面积
func (c *Circle) area() float64 {
	return (PI * float64(c.radius)) * (PI * float64(c.radius))
}

func main() {
	//创建结构体对象,同时给属性赋值
	c1 := Circle{
		radius: 2,
	}

	//调用对象方法
	fmt.Printf("半径为 %d  时,圆周长 = %f, 圆面积 = %f\n", c1.radius, c1.circumference(), c1.area())
}

输出结果

半径为 2  时,圆周长 = 12.560000, 圆面积 = 39.438400

2、访问权限

 C++访问权限

C++访问权限有三种

  • public 公共权限         成员 类内可以访问,类外也可以访问
  • protected 保护权限   成员 类内可以访问,类外不可以访问,继承时,子类可以访问父类成员
  • private 私有权限       成员 类内可以访问,类外不可以访问,继承时,子类不可以访问父类成员
#include <iostream>
using namespace std;
#define PI 3.14

//类 - 人
class Person
{
public:
	//姓名
	string name;
protected:
	//手机号
	string phone;
private:
	//账号密码
	string password;

public:
	void setPerson()
	{
		name = "Tracy";
		phone = "13600000000";
		password = "123";
	}
};

int main()
{
	//类 - 封装 - 访问权限
	Person p1;
	//调用对象公共访问方法
	p1.setPerson();
	cout << "对象访问权限:能够访问public权限:姓名:" << p1.name << endl;
	cout << "对象访问权限:不能访问protected权限:手机号" << endl;
	cout << "对象访问权限:不能访问private权限:密码"  << endl;

	system("pause");

	return 0;
}

输出结果

对象访问权限:能够访问public权限:姓名:Tracy
对象访问权限:不能访问protected权限:手机号
对象访问权限:不能访问private权限:密码

Go语言权限访问

Go语言里访问权限也没有public、protected、private关键字,访问权限如下:

  • 同包下不同文件的全局资源可以随意访问
  • 不同包下资源,首字母大写时可以被不同包访问(可以当作public),首字母小写则不能补不同包访问(可以当作protected)

Go语言结构体对象可以访问自己的所有成员。

3、C++ struct与class区别

struct 成员默认权限是public,class 成员默认权限是private

#include <iostream>
using namespace std;
#define PI 3.14

//类
class C
{
	int id; //默认权限为private
};

//结构体
struct S
{
	int id; //默认权限为public
};

int main()
{
	//类 - 封装 - struct与class区别:struct 成员默认权限是public,class 成员默认权限是private
	//访问类成员
	C c1;
	//c1.id = 5; //报错:不可访问
	cout << "访问类成员 c1.id = 5时,报错:不可访问" << endl;

	//访问结构体成员
	S s1;
	s1.id = 5;	//正常访问
	cout << "访问结构体成员,正常访问, s1.id = " << s1.id << endl;

	system("pause");

	return 0;
}

输出结果

访问类成员 c1.id = 5时,报错:不可访问
访问结构体成员,正常访问, s1.id = 5

4、C++成员属性私有性

  • 将所有成员属性设置为私有,可以自己控制读写权限
  • 对于写权限,可以检查数据的有效性
#include <iostream>
using namespace std;
#define PI 3.14

//类 - 人
class Person
{
private: //以下3个成员属性都设置为私有属性
	//姓名
	string name;
	//手机号
	string phone;
	//账号密码
	string password;

public:
	//成员属性姓名:设置可读可写
	string getName()
	{
		return name;
	}

	void setName(string _name)
	{
		name = _name;
	}

	//成员属性手机号:设置只读
	string getPhone()
	{
		return phone;
	}

	//成员属性账号密码:设置只写,同时检查设置的密码是否大于等于6位
	void setPassword(string _pwd)
	{
		if (_pwd.length() < 6)
		{
			cout << "账号密码长度大于等于6位" << endl;
			return;
		}
		password = _pwd;
	}
};

int main()
{
	//类 - 封装 - 成员属性私有性
	Person p1;

	//调用成员属性姓名:设置可读可写
	p1.setName("Tracy");
	cout << "成员属性姓名:" << p1.getName() << endl;

	//调用成员属性手机号:设置只读
	cout << "成员属性手机号:" << p1.getPhone() << endl;

	//调用属性账号密码:设置只写,同时检查设置的密码是否大于等于6位
	p1.setPassword("123");

	system("pause");

	return 0;
}

输出结果

成员属性姓名:Tracy
成员属性手机号:
账号密码长度大于等于6位

5、C++构造函数与析构函数

5.1、构造函数与析构函数

一个对象或变量没有初始状态,对其使用后果是未知的,同样的,使用完一个对象或变量,没有及时清理,也会造成一定的安全问题。

C++利用构造函数和析构函数解决以上问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我 们做的事情,因此如果不提供构造函数和析构函数,编译器会提供构造函数和析构函数的空实现。

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:类名( 参数列表 ) { 函数体 }

  1. 没有返回值,也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以有重载
  4. 程序在调用对象时会自动调用构造函数,无须手动调用,而且只会调用一次

析构函数语法:~类名() { 函数体 } 

  1. 没有返回值,也不写void
  2. 函数名称与类名相同,且在函数名称前加上符号~
  3. 没有参数,因此不可能发生重载
  4. 程序在对象销毁前会自动调用析构函数,无须手动调用,而且只会调用一次
#include <iostream>
using namespace std;
#define PI 3.14

//类 - 圆
class Circle
{
public:
	//半径
	int radius;

	//构造函数
	/*
		没有返回值,也不写void
		函数名称与类名相同
		构造函数可以有参数,因此可以有重载
		程序在调用对象时会自动调用构造函数,无须手动调用,而且只会调用一次
	*/
	Circle()
	{
		cout << "Circle 构造函数调用" << endl;
	}

	//析构函数
	/*
		没有返回值,也不写void
		函数名称与类名相同,且在函数名称前加上符号~
		没有参数,因此不可能发生重载
		程序在对象销毁前会自动调用析构函数,无须手动调用,而且只会调用一次
	*/
	~Circle()
	{
		cout << "~Circle 析构函数调用" << endl;
	}

	//计算周长
	double circumference()
	{
		return 2 * PI * radius;
	}

	//计算面积
	double area()
	{
		return (PI * radius) * (PI * radius);
	}
};

void f1()
{
	Circle c1; //创建对象时,调用构造函数
	c1.radius = 2;
	cout << "半径为 " << c1.radius << " 时,圆周长 = " << c1.circumference() << ", 圆面积 = " << c1.area() << endl;
	//程序在对象销毁前会自动调用析构函数
}

int main()
{
	//类和对象 - 构造函数与析构函数
	f1();
	
	system("pause");

	return 0;  //程序
}

输出结果

Circle 构造函数调用
半径为 2 时,圆周长 = 12.56, 圆面积 = 39.4384
~Circle 析构函数调用

5.2、构造函数分类及调用

构造函数分类:

  • 按照参数分类:无参构造函数(默认)和有参构造函数
  • 按照类型分类:普通构造函数 和 拷贝构造函数

构造函数调用:

  • 括号法
  • 显示法
  • 隐式转换法

构造函数调用 注意

  • 调用默认构造函数时,不要加()

Circle c1(); //此处编译器会认为是一个函数声明,而不是创建对象,若不实现函数声明,编译时会报错

  • 不要使用拷贝构造函数初始化匿名对象

Circle(c6); //此处编译器会认为 Circle c6; 即创建一个对象 c6,但c6对象已存在,所以编译时会报错

#include <iostream>
using namespace std;
#define PI 3.14

//类 - 圆
class Circle
{
public:
	//半径
	int radius;

	/*
	* 构造函数分类:
		按照参数分类:无参构造函数(默认)和有参构造函数
		按照类型分类:普通构造函数 和 拷贝构造函数
	*/

	//构造函数 - 无参
	Circle()
	{
		cout << "Circle 无参构造函数调用" << endl;
	}

	//构造函数 - 有参
	Circle(int _radius)
	{
		radius = _radius;
		cout << "Circle 有参构造函数调用,参数 _radius = " << _radius << endl;
	}

	//拷贝构造函数
	Circle(const Circle& _circle)
	{
		//将参数拷贝给自己成员
		radius = _circle.radius;
		cout << "Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = " << radius << endl;
	}

	//析构函数
	~Circle()
	{
		cout << "~Circle 析构函数调用" << endl;
	}

	//计算周长
	double circumference()
	{
		return 2 * PI * radius;
	}

	//计算面积
	double area()
	{
		return (PI * radius) * (PI * radius);
	}
};


void f1()
{
	//构造函数调用
	//1、括号法
	Circle c1;	   //调用默认构造函数,即无参的构造函数
	Circle c2(3);  //调用有参构造函数
	Circle c3(c2); //调用拷贝构造函数

	cout << "c2 半径为 " << c2.radius << " 时,圆周长 = " << c2.circumference() << ", 圆面积 = " << c2.area() << endl;
	cout << "c3 半径为 " << c3.radius << " 时,圆周长 = " << c3.circumference() << ", 圆面积 = " << c3.area() << endl;

	//注意:调用默认构造函数时,不要加()
	// Circle c1(); //此处会认为是一个函数声明,而不是创建对象,编译时报错

	//2、显示法
	Circle c4;				//调用默认构造函数,即无参的构造函数
	Circle c5 = Circle(3);	//调用有参构造函数
	Circle c6 = Circle(c5); //调用拷贝构造函数
	Circle(5);				//匿名对象:当前行执行结束后,系统会立即回收掉匿名对象
	cout << "匿名对象执行结束后,系统立即回收掉匿名对象" << endl;

	//注意:不要使用拷贝构造函数初始化匿名对象
	//Circle(c6); //此处编译器会认为 Circle c6; 即创建一个对象 c6,但c6对象已存在,所以编译时会报错

	//3、隐式转换法
	Circle c7 = 6; //相当于 Circle c7 = Circle(6);  调用有参构造函数
	Circle c8 = c7;//相当于 Circle c8 = Circle(c7); 调用拷贝构造函数
}

int main()
{
	//类和对象 - 构造函数与析构函数
	f1();

	system("pause");

	return 0;  //程序
}

输出结果

Circle 无参构造函数调用
Circle 有参构造函数调用,参数 _radius = 3
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 3
c2 半径为 3 时,圆周长 = 18.84, 圆面积 = 88.7364
c3 半径为 3 时,圆周长 = 18.84, 圆面积 = 88.7364
Circle 无参构造函数调用
Circle 有参构造函数调用,参数 _radius = 3
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 3
Circle 有参构造函数调用,参数 _radius = 5
~Circle 析构函数调用
匿名对象执行结束后,系统立即回收掉匿名对象
Circle 有参构造函数调用,参数 _radius = 6
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 6
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用
~Circle 析构函数调用 

5.3、拷贝构造函数调用时机

  • 使用一个已经创建完的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include <iostream>
using namespace std;
#define PI 3.14

//类 - 圆
class Circle
{
public:
	//半径
	int radius;

	//构造函数 - 无参
	Circle()
	{
		cout << "Circle 无参构造函数调用" << endl;
	}

	//构造函数 - 有参
	Circle(int _radius)
	{
		radius = _radius;
		cout << "Circle 有参构造函数调用,参数 _radius = " << _radius << endl;
	}

	//拷贝构造函数
	Circle(const Circle& _circle)
	{
		//将参数拷贝给自己成员
		radius = _circle.radius;
		cout << "Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = " << radius << endl;
	}

	//析构函数
	~Circle()
	{
		cout << "~Circle 析构函数调用" << endl;
	}

	//计算周长
	double circumference()
	{
		return 2 * PI * radius;
	}

	//计算面积
	double area()
	{
		return (PI * radius) * (PI * radius);
	}
};

//1、使用一个已经创建完的对象来初始化一个新对象
void f1()
{
	Circle c1(6);
	Circle c2(c1);
}

void callCircle(Circle _circle) {

}

//2、值传递的方式给函数参数传值
void f2()
{
	Circle c1(5);
	callCircle(c1);
}

Circle returnCircle()
{
	Circle c1(8);
	cout << "returnCircle函数内c1地址:" << &c1 << endl;
	return c1;
}

//3、以值方式返回局部对象
void f3()
{
	Circle c1 = returnCircle();
	cout << "调用returnCircle函数后返回值地址:" << &c1 << endl;
}

int main()
{
	//类和对象 - 构造函数 - 拷贝构造函数调用时机
	/*
		使用一个已经创建完的对象来初始化一个新对象
		值传递的方式给函数参数传值
		以值方式返回局部对象
	*/
	cout << "--- 1、使用一个已经创建完的对象来初始化一个新对象 ---" << endl;
	f1();

	cout << endl << "--- 2、值传递的方式给函数参数传值 ---" << endl;
	f2();

	cout << endl << "--- 3、以值方式返回局部对象 ---" << endl;
	f3();

	system("pause");

	return 0;  //程序
}

输出结果

--- 1、使用一个已经创建完的对象来初始化一个新对象 ---
Circle 有参构造函数调用,参数 _radius = 6
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 6
~Circle 析构函数调用
~Circle 析构函数调用

--- 2、值传递的方式给函数参数传值 ---
Circle 有参构造函数调用,参数 _radius = 5
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 5
~Circle 析构函数调用
~Circle 析构函数调用

--- 3、以值方式返回局部对象 ---
Circle 有参构造函数调用,参数 _radius = 8
returnCircle函数内c1地址:000000AB8FEFF3A4
Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = 8
~Circle 析构函数调用
调用returnCircle函数后返回值地址:000000AB8FEFF4E4
~Circle 析构函数调用

5.4、构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则:

  • 如果用户定义了有参构造函数,C++不再提供默认无参构造函数,但是会提供默认拷贝构造函数
  • 如果用户定义了拷贝构造函数,C++不再提供其他构造函数
#include <iostream>
using namespace std;

//类 - 圆
//构造函数只有有参构造函数
class Circle
{
public:
	//半径
	int radius;

	//构造函数 - 有参
	Circle(int _radius)
	{
		radius = _radius;
		cout << "Circle 有参构造函数调用,参数 _radius = " << _radius << endl;
	}

	//析构函数
	~Circle()
	{
		cout << "~Circle 析构函数调用" << endl;
	}
};

//类 - 圆
//构造函数只有拷贝构造函数
class Circle2
{
public:
	//半径
	int radius;

	//拷贝构造函数
	Circle2(const Circle2& _circle)
	{
		radius = _circle.radius;
		cout << "Circle 拷贝构造函数调用,常量引用参数拷贝结果 radius = " << radius << endl;
	}

	//析构函数
	~Circle2()
	{
		cout << "~Circle 析构函数调用" << endl;
	}
};

void f1()
{
	//构造函数只有有参构造函数
	//Circle c1;  //使用无参构造函数创建对象,报错:不存在默认构造函数
	Circle c2(5); //使用有参构造函数创建对象,正常
	Circle c3(c2); //使用拷贝构造函数创建对象,正常
	cout << "构造函数只有有参构造函数,使用拷贝构造函数创建对象时,c3.radius = " << c3.radius << endl;
}

void f2()
{
	//构造函数只有拷贝构造函数,没有提供默认的构造函数
	//Circle2 c1;  //使用无参构造函数创建对象,报错:不存在默认构造函数
}

int main()
{
	//类和对象 - 构造函数调用规则
	/*
	 默认情况下,C++编译器至少给一个类添加3个函数:
		默认构造函数(无参,函数体为空)
		默认析构函数(无参,函数体为空)
		默认拷贝构造函数,对属性进行值拷贝

	构造函数调用规则:
		如果用户定义了有参构造函数,C++不再提供默认无参构造函数,但是会提供默认拷贝构造函数
		如果用户定义了拷贝构造函数,C++不再提供其他普通构造函数
	*/
	cout << "--- 1、如果用户定义了有参构造函数,C++不再提供默认无参构造函数,但是会提供默认拷贝构造函数 ---" << endl;
	f1();

	cout << endl << "--- 2、如果用户定义了拷贝构造函数,C++不再提供其他构造函数 ---" << endl;
    f2();

	system("pause");

	return 0;  //程序
}

输出结果

--- 1、如果用户定义了有参构造函数,C++不再提供默认无参构造函数,但是会提供默认拷贝构造函数 ---
Circle 有参构造函数调用,参数 _radius = 5
构造函数只有有参构造函数,使用拷贝构造函数创建对象时,c3.radius = 5
~Circle 析构函数调用
~Circle 析构函数调用

--- 2、如果用户定义了拷贝构造函数,C++不再提供其他构造函数 ---

5.5、深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

注:

如果属性有堆区开辟空间的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

浅拷贝存在的问题

以下一成员属性在堆区开辟空间

#include <iostream>
using namespace std;

//类 - 圆
class Circle
{
public:
	//半径
	int radius;
	//长度(仅作示例)
	int* length;

	Circle(int _radius, int _length)
	{
		radius = _radius;
		length = new int(_length); //堆区开辟空间
	}

	//析构函数
	~Circle()
	{
		//将堆区开辟的空间释放
		if (length != NULL)
		{
			delete length;
			length = NULL;
		}
		cout << "~Circle 析构函数调用" << endl;
	}
};

int main()
{
	//类和对象 - 构造函数 - 深拷贝与浅拷贝
	/*
		浅拷贝:简单的赋值拷贝操作
		深拷贝:在堆区重新申请空间,进行拷贝操作
	*/
	cout << "--- 浅拷贝存在的问题 ---" << endl;
	Circle c1(2, 5);
	Circle c2(c1);
	cout << "--- 析构函数手动释放堆区空间时,抛出异常 ---" << endl;
	//原因:默认的拷贝构造函数为浅拷贝,即简单复制,当c2空间释放了,length指针堆上分配的空间也被释放,再释放c1时,调用析构函数,释放length时,由于已经被释放,因此抛异常
	
	system("pause");

	return 0;  //程序
}

输出结果后,关闭程序,抛出异常:

原因:默认的拷贝构造函数为浅拷贝,即简单复制,当c2空间释放了,length指针堆上分配的空间也被释放,再释放c1时,调用析构函数,释放length时,由于已经被释放,再次重复释放,因此抛异常。

解决方案

 提供拷贝构造函数,实现深拷贝

#include <iostream>
using namespace std;

//类 - 圆
class Circle
{
public:
	//半径
	int radius;
	//长度(仅作示例)
	int* length;

	Circle(int _radius, int _length)
	{
		radius = _radius;
		length = new int(_length); //堆区开辟空间
	}

	//解决浅拷贝的问题:拷贝构造函数实现深拷贝
	Circle(const Circle& _circle)
	{
		radius = _circle.radius;
		//length = _circle.length; //编译器默认提供浅拷贝
		length = new int(*_circle.length); //堆区开辟空间,实现深拷贝
	}

	//析构函数
	~Circle()
	{
		//将堆区开辟的空间释放
		if (length != NULL)
		{
			delete length;
			length = NULL;
		}
		cout << "~Circle 析构函数调用" << endl;
	}
};

int main()
{
	//类和对象 - 构造函数 - 深拷贝与浅拷贝
	/*
		浅拷贝:简单的赋值拷贝操作
		深拷贝:在堆区重新申请空间,进行拷贝操作
	*/
	cout << "--- 解决浅拷贝存在的问题:拷贝构造函数实现深拷贝 ---" << endl;
	Circle c1(2, 5);
	Circle c2(c1);

	system("pause");

	return 0;  //程序
}

5.6、初始化列表

初始化列表用来初始化属性

语法:

构造函数(): 属性1(值1),属性2(值2)...{}        //初始化默认值

构造函数(参数列表): 属性1(参数1),属性2(参数2)...{}       

#include <iostream>
using namespace std;

//类 - 圆 - 初始化列表方式一
class Circle
{
public:
	//半径
	int radius;

	//初始化列表,为成员属性设置初始值
	Circle() :radius(5)
	{
		cout << "初始化列表Circle() :radius(5), radius = " << radius << endl;
	}
};

//类 - 圆 - 初始化列表方式二
class Circle2
{
public:
	//半径
	int radius;

	//初始化列表,为成员属性设置初始值
	Circle2(int _radius) :radius(_radius)
	{
		cout << "初始化列表Circle2(int _radius) :radius(_radius), radius = " << radius << endl;
	}
};

int main()
{
	//类和对象 - 构造函数 - 初始化列表
	Circle c1;
	Circle2 c2(3);

	system("pause");

	return 0;  //程序
}

输出结果

初始化列表Circle() :radius(5), radius = 5
初始化列表Circle2(int _radius) :radius(_radius), radius = 3

5.7、类对象作为类成员,构造函数与析构函数先后执行顺序 

  • 构造顺序:先调用对象成员的构造函数,再调用本类的构造函数
  • 析构顺序:与构造顺序相反,即先调用本类的析构函数,再调用对象成员的析构函数
#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	//构造函数
	Point(int _x, int _y) :x(_x), y(_y)
	{
		cout << "Point 构造函数" << endl;
	}

	//析构函数
	~Point()
	{
		cout << "Point 析构函数" << endl;
	}
};

//类 - 圆 
class Circle
{
public:
	//半径
	int radius;
	//圆心 - 类对象成员
	Point point;

	//构造函数
	// Point point(_x, _y);
	Circle(int _radius, int _x, int _y):radius(_radius),point(_x,_y) 
	{
		cout << "Circle 构造函数" << endl;
	}

	//析构函数
	~Circle()
	{
		cout << "Circle 析构函数" << endl;
	}
};

int main()
{
	//类和对象 - 构造函数 - 类对象作为类成员,构造函数与析构函数先后执行顺序 
	/*
		构造顺序:先调用对象成员的构造函数,再调用本类的构造函数
		析构顺序:与构造顺序相反,即先调用本类的析构函数,再调用对象成员的析构函数
	*/
	Circle(2, 3, 4);

	system("pause");

	return 0;  //程序
}

输出结果

Point 构造函数
Circle 构造函数
Circle 析构函数
Point 析构函数

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 学习(11)类和对象、封装、访问权限、成员属性私有性、构造函数与析构函数 的相关文章

  • 使用链表进行堆排序

    我想知道是否有人曾经使用链表进行堆排序 如果他们可以提供代码 我已经能够使用数组进行堆排序 但尝试在链表中进行排序似乎不切实际 而且在你知道的地方很痛苦 我必须为我正在做的项目实现链接列表 任何帮助将不胜感激 我也用C 答案是 你不想在链表
  • 与 for_each 或 std::transform 一起使用时,如何调用 C++ 函子构造函数

    我以前从未使用过 C 函子 所以我只是想了解它们是如何工作的 例如假设我们有这个函子类 class MultiplyBy private int factor public MultiplyBy int x factor x int ope
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • C# 中一次性对象克隆会导致内存泄漏吗?

    检查这个代码 class someclass IDisposable private Bitmap imageObject public void ImageCrop int X int Y int W int H imageObject
  • Selenium - C# - Webdriver - 无法找到元素

    在 C 中使用 selenium 我试图打开浏览器 导航到 Google 并找到文本搜索字段 我尝试下面的 IWebDriver driver new InternetExplorerDriver C driver Navigate GoT
  • 防止控制台应用程序中的内存工作集最小化?

    我想防止控制台应用程序中的内存工作集最小化 在Windows应用程序中 我可以这样做覆盖 SC MINIMIZE 消息 http support microsoft com kb 293215 en us fr 1 但是 如何在控制台应用程
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • OpenGL:如何检查用户是否支持glGenBuffers()?

    我检查了文档 它说 OpenGL 版本必须至少为 1 5 才能制作glGenBuffers 工作 用户使用的是1 5版本但是函数调用会导致崩溃 这是文档中的错误 还是用户的驱动程序问题 我正在用这个glGenBuffers 对于VBO 我如
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • LinkLabel 无下划线 - Compact Framework

    我正在使用 Microsoft Compact Framework 开发 Windows CE 应用程序 我必须使用 LinkLabel 它必须是白色且没有下划线 因此 在设计器中 我将字体颜色修改为白色 并在字体对话框中取消选中 下划线
  • MySQL 连接器 C++ 64 位在 Visual Studio 2012 中从源代码构建

    我正在尝试建立mySQL 连接器 C 从源头在视觉工作室2012为了64 bit建筑学 我知道这取决于一些boost头文件和C 连接器 跑步CMake生成一个项目文件 但该项目文件无法编译 因为有一大堆非常令人困惑的错误 这些错误可能与包含
  • 使用 gcc 时在头文件中查找定义的好方法是什么?

    在使用 gcc 时 有人有推荐的方法在头文件中查找定义吗 使用 MSVC 时 我只需右键单击并选择 转到定义 这非常好 我使用过 netbeans gcc 它确实有代码帮助 包括到定义的超链接 所以这是一种选择 但是 我想知道是否有任何其他
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • C:设置变量范围内所有位的最有效方法

    让我们来int举个例子 int SetBitWithinRange const unsigned from const unsigned to To be implemented SetBitWithinRange应该返回一个int其中所有
  • 构建 C# MVC 5 站点时项目之间的处理器架构不匹配

    我收到的错误如下 2017 年 4 月 20 日构建 13 23 38 C Windows Microsoft NET Framework v4 0 30319 Microsoft Common targets 1605 5 警告 MSB3
  • 如何组合两个 lambda [重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中组合两个 lambda 表达式 https stackoverflow com questions 1717444 combining two lamba expressions in c
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • .Net Reactive Extensions Framework (Rx) 是否考虑拓扑顺序?

    Net 反应式扩展框架是否按拓扑顺序传播通知以最大限度地减少更新量 就像 Scala Rx 所做的那样 Net 反应式扩展 Rx 是否可以 https github com lihaoyi scala rx wiki How it Work

随机推荐

  • Python爬取某短视频热点

    随着短视频的大火 不仅可以给人们带来娱乐 还有热点新闻时事以及各种知识 刷短视频也逐渐成为了日常生活的一部分 本 文以一个简单的小例子 简述如何通过Pyhton依托Selenium来爬取短视频 仅供学习分享使用 如有不足之处 还请指正 涉及
  • pyspark环境安装历史难题终于解决

    path JAVA HOME里面的D JAVA 1 jdk1 8 0 152 bin一定要全并且对应上 踩坑记录 已解决 报错 WARN ProcfsMetricsGetter Exception when trying to comput
  • 基于Java的OA系统的设计与实现

    源码及论文下载 http www byamd xyz tag java 摘 要 学习和研究办公自动化中涉及到的知识和技术是实现办公自动化系统的前提条件 通过学习研究 掌握了其中的关键技术之后 结合自身的理解 对其做出了相应的表述 同时也成功
  • 【第03例】IPD体系进阶

    目录 前言 专栏目录 具体内容 IPD 相关专栏推荐 专栏列表 作者简介 前言 今天继续来讲讲 IPD 中涉及的几个评审点 ADCP 是英文 Av
  • 彻底理解coookie、session、token

    一 发展史 1 很久很久以前 web基本上就是文档的浏览而已 既然是浏览 作为服务器 不需要记录谁在某一段时间里都浏览了什么文档 每次请求都是一个新的HTTP协议 就是请求加响应 尤其是我不用记住是谁刚刚发了HTTP请求 每个请求对我来说都
  • Linux下的Oracle连接

    1 进入Oracle su oracle 2 开启监听器 oracle localhost root lsnrctl status oracle localhost root lsnrctl start oracle localhost r
  • 微信小程序自定义 tab-bar(基于 wepy)

    背景 微信小程序提供的原生 tab bar 功能简单 样式单一 无法满足业务需求 项目中使用的是 wepy 1 x 框架 实现原理与原生类似 方案 一 使用组件 在每个Tab页引入 修改全局配置 app wpy export default
  • CloudCompare--安装和简单的使用方法

    CloudCompare 安装和简单的使用方法 CloudCompare工具是一个非常好的处理点云数据的开源工具 有个不错的框架 很多公司对该工具进行二次开发以满足公司需要 第一次使用CloudCompare感觉非常好用 有兴趣的可以多了解
  • C语言进阶知识点(持续跟新)

    还是有点儿进阶的知识点 1 大段 小段内存模型 int val 0x12345678 int p1 val char p2 char p1 printf x n p2 p2 printf x n p2 short p3 val printf
  • windows server 2012 双网卡配置

    别用route 命令 在使用最新版的windows server 2012的时候 当存在两个或者多个网段的时候 就可以采用双网卡的方式来添加和配置路由 具体的设置方法如下 网段1 192 168 0 0 网段2 192 168 1 0 20
  • Go的 context 包的使用

    文章目录 背景 简介 主要方法 获得顶级上下文 当前协程上下文的操作 创建下级协程的Context 场景示例 背景 在父子协程协作过程中 父协程需要给子协程传递信息 子协程依据父协程传递的信息来决定自己的操作 这种需求下可以使用 conte
  • 337. House Robber III

    The thief has found himself a new place for his thievery again There is only one entrance to this area called the root B
  • 我们来浅谈代码语言的魅力

    01 浅谈 V8 Hidden Classes 和 Inline Caches Javascript 是动态的 基于属性链的语言 V8 是流行的 JavaScript 运行引擎 我们知道在运行时可以改变对象的属性和类型 为了定位对象的属性和
  • pb使用记录 关于pbt、pbr、pbd

    pb使用记录 关于pbl pbt pbr pbd 最近使用pb修改程序 遇到一些基础问题 之前有过了解但是几年没有碰过PB有些忘了 简单记录一下 1 关于pbl pbt pbr pbd pbt powerbuilder target 是8以
  • Java代码的静态编译和动态编译中的问题比较(1)

    Java 应用程序的性能经常成为开发社区中的讨论热点 因为该语言的设计初衷是使用解释的方式支持应用程序的可移植性目标 早期 Java 运行时所提供的性能级别远低于 C 和 C 之类的编译语言 尽管这些语言可以提供更高的性能 但是生成的代码只
  • 一篇文章带你了解JavaScript中的变量,作用域和内存问题

    作者 Jeskson 来源 达达前端小酒馆 1 在JavaScript中的变量分别区分为两种 一种为基本类型值 一种为引用类型值 基本类型值指的是简单的数据段 引用类型值为可能由多个值组成的对象 引用类型的值是保存在内存中的对象 JavaS
  • maven install的时候报Unable to find main class

    目录 问题描述 解决办法 解决方案一 添加一个主函数 解决方案二 将不是web工程的设置跳过 解决方案三 打包插件的作用本质上就是将当前项目所依赖的jar打包到一块 这样jar包就可以运行了 我们完全可以把parent的pom xml的bu
  • tauri使用github进行打包和自动更新教程

    之前的几篇文章介绍了tauri的基本安装 本地打包等方法 本文将接着就前几篇文章进行继续阐述 着重介绍tauri介绍tauri以github为后台服务进行打包 更新 以及tauri配置启动图 一 tauri使用github进行打包 1 首先
  • 学编程买什么电脑最好?

    补充下背景 在编程界 编程设备 电脑 有两个世界 一个是普通世界 这个世界里 程序员写代码的电脑和大众玩游戏看电影上网做ppt的电脑一样 就是你手头的普通电脑 什么电脑都行 另一个世界 是专业世界 是非windows行业的专业 高端 杨村白
  • C++ 学习(11)类和对象、封装、访问权限、成员属性私有性、构造函数与析构函数

    面向对象的特点 封装 继承 多态 万事万物皆为对象 对象上有其属性和行为 方法 1 封装 将属性与行为作为一个整体 表现生活中的事物 将属性和行为加以权限控制 public private等 C 封装 语法 class 类名 访问权限 属性