c++面向对象之类

一、类的定义

class 类名{
     成员属性
     构造函数
     析构函数
     成员函数
}

Person.h

#include <string>
#include <iostream>
using namespace std;


class Person {
    
    
	int m_age;
	string m_name;

	Person();

	Person(int age,string name);

	~Person();

	int getAge();

	void setAge(int age);

	string getName();

	void setName(string name);
};


Person.cpp

#include "Person.h"

Person::Person() {
    
    }

Person::Person(int age, string name) :m_age(age), m_name(name) {
    
    }

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

int Person::getAge() {
    
    
	return m_age;
}

void Person::setAge(int age) {
    
    
	m_age = age;
}

string Person::getName() {
    
    
	return m_name;
}

void Person::setName(string name) {
    
    
	m_name = name;
}
  • 如果要使用string类型的话,第一、需要添加#include <string>;第二、需要添加std的命名空间(using namespace std;)或者使用std::string
  • 类里面的所有成员属性和函数默认都是私有的(private)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    只需要调整访问权限为public即可。
    在这里插入图片描述
    在这里插入图片描述

二、类的实例对象创建

2.1、声明的时候,在栈中创建对象

Person person;

在这里插入图片描述

  • 在栈中创建的对象会随着main函数执行的结束而销毁

2.2、使用new,在堆中创建对象

Person *person = new Person();

在这里插入图片描述

  • 使用new创建的是一个指针
  • main函数执行结束,person对象并没有调用析构函数,说明该对象还没有销毁,需要手动调用delete
    在这里插入图片描述

2.3、使用malloc,在堆中创建对象

Person *person = (Person*)malloc(sizeof(Person));

在这里插入图片描述

  • malloc创建的也是一个指针
  • malloc创建对象的时候,没有调用构造方法,只是在堆中开辟了所需要大小的内存空间
  • 需要调用free方法,来销毁创建的对象,释放内存
    在这里插入图片描述
  • 无论是使用malloc创建对象,以及使用free销毁对象,都不会调用类的构造函数析构函数

三、类的成员属性的初始化

3.1、无构造函数的类

Person.h

#include <string>
#include <iostream>
using namespace std;


class Person {
    
    
	int m_age;
	string m_name;
public:
	~Person();

	int getAge();

	void setAge(int age);

	string getName();

	void setName(string name);
};

Person.cpp

#include "Person.h"

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

int Person::getAge() {
    
    
	return m_age;
}

void Person::setAge(int age) {
    
    
	m_age = age;
}

string Person::getName() {
    
    
	return m_name;
}

void Person::setName(string name) {
    
    
	m_name = name;
}

在这里插入图片描述

  • 对于无构造方法的类,只有只用new创建的对象的成员属性才会被初始化。

3.2、有构造函数的类

Person.h

#include <string>
#include <iostream>
using namespace std;


class Person {
    
    
	int m_age;
	string m_name;
public:
	Person();

	Person(int age,string name);

	~Person();

	int getAge();

	void setAge(int age);

	string getName();

	void setName(string name);
};


Person.cpp

#include "Person.h"

Person::Person() {
    
    
	cout << "构造方法调用" << endl;
}

Person::Person(int age, string name) :m_age(age), m_name(name) {
    
    }

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

int Person::getAge() {
    
    
	return m_age;
}

void Person::setAge(int age) {
    
    
	m_age = age;
}

string Person::getName() {
    
    
	return m_name;
}

void Person::setName(string name) {
    
    
	m_name = name;
}

在这里插入图片描述

  • 如果类有构造函数,但是构造函数里面并没有对成员属性进行初始化的话,无论何种方式创建对象,对象的成员属性都不会被初始化

四、类的构造函数

4.1、定义

构造函数,是一种特殊的方法(没有返回值,方法名和类名相同)。 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值。

4.2、实现

Test.h

#pragma once
class Test
{
    
    
public:
	int number_;

	Test();
	Test(int number);
};

Test.cpp

#include "Test.h"

Test::Test() {
    
    }

Test::Test(int number) {
    
    
    number_ = number;
}

  • 构造函数没有返回值
  • 构造函数的函数名称与类名相同
  • 构造函数可以重载

4.3、初始化列表

4.3.1、格式

标准构造函数格式:

Test::Test(int number) {
    
    
    number_ = number;
}

初始化列表格式:

Test::Test(int number) :number_(number) {
    
    }

4.3.2、优势

  • 传入参数可以是表达式
int a = 10;
Test* test = new Test(a+10);

在这里插入图片描述

  • 传入参数可以是函数
#include <iostream>
#include "Test.h"
using namespace std;

int add(int a,int b);
int main() {
    
    
	int a = 10;
	Test* test = new Test(a+add(a,2));
	cout << test->number_ << endl;
	return 0;

}

int add(int a, int b) {
    
    
	return a * b;
}

在这里插入图片描述

  • 搭配默认参数,创建对象时,构造函数更灵活
    PS:如果是采用声明和实现分离的方式定义类的话,初始化列表是写在头文件中的
    Test.h
#pragma once

class Test
{
    
    
public:
	int number_;

	Test(int number=0) :number_(number) {
    
    };
};
#include <iostream>
#include "Test.h"
using namespace std;

int main() {
    
    
	Test *test=new Test();
	cout << test->number_ << endl;

	Test *test1=new Test(18);
	cout << test1->number_ << endl;
	return 0;

}

在这里插入图片描述

4.4、构造函数互调

  • 构造函数的互调也是使用初始化列表的形式实现的
#include "Test.h"

Test::Test() :Test(10) {
    
    }

Test::Test(int number) {
    
    
    number_ = number;
}

在这里插入图片描述

4.5、拷贝构造函数

拷贝构造函数是构造函数的一种,也称复制构造函数,它只有一个参数,参数类型是本类的引用。

拷贝构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。

如果类不写拷贝构造函数,编译器就会自动生成拷贝构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的拷贝,即使得目标对象的每个成员变量都变得和源对象相等。编译器自动生成的拷贝构造函数称为“默认拷贝构造函数”。

PS:默认构造函数(即无参构造函数)不一定存在,但是拷贝构造函数总是会存在。

4.5.1、对象赋值的时候,会调用拷贝构造函数

Copy.h

#pragma once
#include <iostream>
#include <string>
using namespace std;
class Copy
{
    
    
public:
	int mAge;
	string mName;
public:
	Copy(int age=0, string name="") :mAge(age), mName(name) {
    
    }
	Copy(const Copy& copy) :mAge(copy.mAge), mName(copy.mName) {
    
    };
	~Copy();

};

Copy.cpp

#include "Copy.h"

Copy::Copy(const Copy& copy) {
    
    
	cout << "拷贝构造函数" << endl;
}
Copy::~Copy()
{
    
    
}

main.cpp

#include <iostream>
#include "Copy.h"
using namespace std;

int main() {
    
    

	Copy copy1;
	Copy copy2 = copy1;
	getchar();
	return 0;

}

在这里插入图片描述

4.5.2、对象作为函数的入参时会调用对象的拷贝构造函数

Utils.h

#pragma once
#include<string>
#include "Copy.h"
using namespace std;
class Utils
{
    
    
public:
	const static  string BASIC_URL;
	static string formatInt2String(int number);
	static void display(Copy copy);
};

Utils.cpp

#include "Utils.h"

 const string Utils::BASIC_URL = "http://www.baidu.com";

 string Utils::formatInt2String(int number)
 {
    
    
	 return to_string(number);
 }

 void Utils::display(Copy copy) {
    
    
	 cout << copy.mName << endl;
 }

main.cpp

#include <iostream>
#include "Copy.h"
#include "Utils.h"
using namespace std;

int main() {
    
    

	Copy copy1;
	Utils::display(copy1);
	getchar();
	return 0;

}

在这里插入图片描述
PS:为了避免函数调用产生多余的临时拷贝,所以,当对象作为形参时,要使用引用或者指针。
在这里插入图片描述
在这里插入图片描述
此时函数调用就没有调用对象的拷贝构造函数。

4.6、运算符重载

运算符重载是一种形式的多态,运算符重载可使代码看起来更自然。

operator + <操作符>+()

4.6.1、可重载的运算符

+ - * / % ^
& | ~= ! = <
> += -= /= *= %=
^= &= |= << >> <<=
>>= == != <= >= &&
|| ++ - - , ->* ->
() [] new delete new [] delete []

OperatorOverride.h

#pragma once
class OperatorOverride
{
    
    
public:
	OperatorOverride(int age=16) :mAge(age) {
    
    }
	~OperatorOverride();
	int getAge();
	void setAge(int age);
private:
	int mAge;
};

OperatorOverride.cpp

#include "OperatorOverride.h"


OperatorOverride::~OperatorOverride()
{
    
    
}

int OperatorOverride::getAge()
{
    
    
	return mAge;
}

void OperatorOverride::setAge(int age)
{
    
    
	mAge = age;
}

4.6.2、一元运算符重载

一元运算符即只对一个操作数进行操作的运算符,例如:!obj、-obj、++obj 、obj++ 或 obj-- 等等
OperatorOverride.h

#pragma once
#include <iostream>
using namespace std;

class OperatorOverride
{
    
    
public:
	OperatorOverride(int age=16,bool adult=0) :mAge(age),isAdult(adult) {
    
    }
	~OperatorOverride();
	int getAge();
	void setAge(int age);
	bool getIsAdult();
	void setIsAdult(bool adult);
	void display();
	
	void operator !();
	OperatorOverride& operator ++();
	OperatorOverride operator ++(int);
private:
	int mAge;
	bool isAdult;
};

OperatorOverride.cpp

#include "OperatorOverride.h"


OperatorOverride::~OperatorOverride()
{
    
    
}

int OperatorOverride::getAge()
{
    
    
	return mAge;
}

void OperatorOverride::setAge(int age)
{
    
    
	mAge = age;
}

bool OperatorOverride::getIsAdult()
{
    
    
	return isAdult;
}

void OperatorOverride::setIsAdult(bool adult)
{
    
    
	isAdult = adult;
}

void OperatorOverride::display()
{
    
    
	cout << "Age is:" << mAge << endl;
	cout << "Are you is adult:" << isAdult << endl;
}

void OperatorOverride::operator!()
{
    
    
	isAdult = !isAdult;
}

OperatorOverride& OperatorOverride::operator++()
{
    
    
	mAge += 1;
	return *this;
}

OperatorOverride OperatorOverride::operator++(int)
{
    
     
	OperatorOverride o(mAge,isAdult);
	mAge++;
	return o;
}

main.cpp

#include <iostream>
#include "OperatorOverride.h"
using namespace std;

int main() {
    
    

	OperatorOverride oo1(18,false);
	oo1.display();
	cout << "-----------初始化------------" << endl;
	!oo1;
	oo1.display();
	cout << "-----------重载!------------" << endl;
	++oo1;
	oo1.display();
	cout << "-----------重载前置++------------" << endl;
	(oo1++).display();
	cout << "-----------重载后置++------------" << endl;

	getchar();
	return 0;

}

4.6.2、二元运算符重载

二元运算符即需要两个参数的运算符,例如:加运算符(+)、减运算符(-)、乘运算符(*)、除运算符(/)。
OperatorOverride.h

OperatorOverride operator +(OperatorOverride& oo);

OperatorOverride.cpp

OperatorOverride OperatorOverride::operator+(OperatorOverride& oo)
{
    
    

	return OperatorOverride(mAge+oo.getAge());
}

4.6.3、关系运算符重载

C++ 允许重载任何一个关系运算符(例如 < 、 > 、 <= 、 >= 、 == 等),重载后的关系运算符可用于比较类的对象。

OperatorOverride.h

bool operator >(OperatorOverride& oo) const;
bool operator <(OperatorOverride& oo)const;
bool operator ==(OperatorOverride& oo)const;

OperatorOverride.cpp

bool OperatorOverride::operator>(OperatorOverride& oo) const
{
    
    
	return mAge>oo.getAge();
}

bool OperatorOverride::operator<(OperatorOverride& oo)const
{
    
    
	return mAge < oo.getAge();
}

bool OperatorOverride::operator==(OperatorOverride& oo)const
{
    
    
	return mAge==oo.getAge();
}

main.cpp

#include <iostream>
#include "OperatorOverride.h"
using namespace std;

int main() {
    
    

	OperatorOverride oo1(18,true);
	OperatorOverride oo2(20, false);
	bool state = oo1 > oo2;
	cout << "oo1>oo2:" << state<< endl;
	state = oo1 < oo2;
	cout << "oo1<oo2:" << state << endl;
	state = oo1 == oo2;
	cout << "oo1==oo2:" << state << endl;
	getchar();
	return 0;

}

在这里插入图片描述

4.7、补充

4.7.1、如果不创建构造函数,创建对象的时候会创建默认的构造函数吗?

Test.h

#pragma once
class Test
{
public:
	int number_=0;
};

在这里插入图片描述

  • 如果成员属性默认赋值,则会生成默认的构造函数,还会调用默认的构造函数
#pragma once
class Test
{
public:
	int number_;
};

在这里插入图片描述

  • 如果成员属性没有赋值,则不会生成默认的构造函数。

4.7.2、创建对象的时候,new test和new Test()有什么区别

  • 如果类没有显示声明构造函数,都不会调用创建构造函数,但是带括号的会初始化成员属性
    在这里插入图片描述

在这里插入图片描述

  • 如果自定义构造函数,则都会调用构造方法,并且都不会初始化成员属性
    在这里插入图片描述
    在这里插入图片描述

五、静态(static)成员属性和函数

5.1.1、静态成员属性

静态成员属性实际上是类域中的全局变量,且类的静态成员属性在类内只能声明**,定义和初始化必须在类外**

静态成员属性被类的所有对象共享,包括该类的派生类对象,所以静态成员属性为类内的全局变量
Utils.h

#pragma once
#include<string>
#include "Copy.h"
using namespace std;
class Utils
{
    
    
public:
	const static  string BASIC_URL;
};

Utils.cpp

#include "Utils.h"

 const string Utils::BASIC_URL = "http://www.baidu.com";

5.1.2、静态成员函数

类的静态成员函数可以在没有定义任何对象前使用,即无须创建任何对象实例就可以使用此成员函数

静态成员函数不可调用类的非静态成员,且静态成员函数不包含this指针,非静态成员必须与特定对象相对
Utils.h

#pragma once
#include<string>
#include "Copy.h"
using namespace std;
class Utils
{
    
    
public:
	static string formatInt2String(int number);

	static void display(Copy &copy);
};

Utils.cpp

#include "Utils.h"

  string Utils::formatInt2String(int number)
 {
    
    
	 return to_string(number);
 }


 void Utils::display(Copy &copy) {
    
    
	 cout << copy.mName << endl;
 }

猜你喜欢

转载自blog.csdn.net/u011557841/article/details/130728361