文章目录
前言
本篇文章主要介绍了C++类和对象
1. 类和对象的定义
1.1 类定义的格式:
class 类名{
public:
//<共有数据和函数>
protected:
//<保护数据和函数>
private:
//<私有数据和函数>
};
/*Person类的定义*/
#include<iostream>
using namespace std;
class Person {
public:
/*函数既可以在类内定义,也可以先在类内声明,在类的外部l定义,
在类外定义时要指定命名空间为Person(类名)*/
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
};
void setName(string name);
void setAge(int age);
private:
string name;
int age;
};
void Person::setName(string name) {
this->name = name;//this是一个特殊的指针,指向这个对象本身
}
void Person::setAge(int age) {
this->age = age;
}
1.2 类的构造函数
(1)作用:在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。
(2)特点:
1)自动调用(在创建新对象时,自动调用)
2)构造函数的函数名,和类名相同
3)构造函数没有返回类型
4)可以有多个构造函数(即函数重载形式)
(3)构造函数的种类:
默认构造函数
自定义的构造函数
拷贝构造函数
赋值构造函数
1.2.1 默认构造函数
没有参数的构造函数,称为默认构造函数。
(1)合成的默认构造函数:
1)如果数据成员使用了“类内初始值”,就使用这个值来初始化数据成员(C++11)
2)否则,就使用默认初始化(实际上,不做任何初始化)
class Person {
public:
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
};
private:
string name = "未命名";//c11之后才支持这样初始化
int age = 0;
};
(2)自定义的默认构造函数
class Person {
public:
Person();//默认构造函数的声明
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
};
private:
string name = "未命名";
int age = 0;
};
Person::Person() {
cout << "调用了自定义的默认构造函数" << endl;
}
1.2.2 自定义的构造函数
class Person {
public:
Person();
Person(string name, int age);
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
};
private:
string name = "未命名";
int age = 0;
};
Person::Person() {
cout << "调用了自定义的默认构造函数" << endl;
}
Person::Person(string name, int age) {
this->name = name;
this->age = age;
cout << "调用了自定义的构造函数" << endl;
}
1.2.3 拷贝构造函数
(1)自定义的拷贝构造函数(参数必须是其他该类对象的引用)
class Person {
public:
Person();
Person(string name, int age);
Person(const Person &person);
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
};
private:
string name = "未命名";
int age = 0;
};
Person::Person() {
cout << "调用了自定义的默认构造函数" << endl;
}
Person::Person(string name, int age) {
this->name = name;
this->age = age;
cout << "调用了自定义的构造函数" << endl;
}
Person::Person(const Person &person) {
cout << "调用自定义的拷贝构造函数" << endl;
name = person.name;
age = person.age;
}
(2)默认的拷贝构造函数
不定义拷贝构造函数,编译器会生成“合成(默认)的拷贝构造函数”,但合成的拷贝构造函数使用的是浅拷贝,而自定义的拷贝构造函数我们可以定义为深拷贝
#include<iostream>
using namespace std;
class Person {
public:
Person();
Person(string name, int age, const char *addr);
Person(const Person &person);
void printBasicInfo() {
cout << this->name << endl;
cout << this->age << endl;
cout << this->addr << endl;
printf("%p\n", &this->addr[0]);
};
void setAddr(const char *newAddr) {
if (!newAddr) {
return;
}
strcpy_s(addr, 64, newAddr);
}
private:
string name = "未命名";
int age = 0;
char *addr = NULL;
};
Person::Person() {
cout << "调用了自定义的默认构造函数" << endl;
name = "未命名";
age = 0;
}
Person::Person(string name, int age,const char *addr) {
cout << "调用了自定义的构造函数" << endl;
this->name = name;
this->age = age;
this->addr = new char[64];
strcpy_s(this->addr, 64, addr);
}
Person::Person(const Person &person) {
cout << "调用自定义的拷贝构造函数" << endl;
name = person.name;
age = person.age;
//(1)浅拷贝:这里只是单纯的将person.addr的存储的地址给addr,所以addr与person.addr指向了同一内存空间
// 所以当addr或者person.addr的值改变时,他们会同时改变
addr = person.addr;
//(2)深拷贝:这里我们给addr重新分配内存空间,
//然后把person.addr所指向内存空间的值拷贝给addr所指向的内存空间
/*addr = new char[64];
strcpy_s(addr, 64, person.addr);*/
}
int main(void) {
Person peo2("Tree", 20,"China");
Person peo3 = peo2;
Person peo4(peo2);
peo2.setAddr("USA");
cout << endl << "peo2:" << endl;
peo2.printBasicInfo();
cout << endl << "peo3:" << endl;
peo3.printBasicInfo();
cout << endl << "peo4:" << endl;
peo4.printBasicInfo();
system("pause");
return 0;
}
浅拷贝效果:
深拷贝效果:
(3)调用拷贝构造函数的几种情况:
1. 调用函数时,实参是对象,形参不是引用类型, 如果函数的形参是引用类型,就不会调用拷贝构造函数(或者用指针)
void printPersonInfo(Person peo) {//调用一次
peo.printBasicInfo();
}
2. 函数的返回类型是类,而且不是引用类型
Person alterPersonAddr(Person &peo) {
peo.setAddr("Japan");
peo.printBasicInfo();
return peo; //调用一次
}
3. 对象数组的初始化列表中,使用对象。
Person peo1("Tree", 20, "China");
Person peo2("Rock", 1024, "China");
Person peo3("Martin", 88, "China");
Person peos[] = { peo1,peo2,peo3 };//调用三次
1.2.4 赋值构造函数
默认赋值构造函数也是进行浅拷贝,在自定义的赋值构造函数中可以实现深拷贝
//赋值构造函数的声明,实际上是进行运算符重载
Person& operator=(const Person &people);
//实现
Person& Person::operator=(const Person &people) {
if(this == &people){
return *this;//检测是不是给自己赋值P1 = P1
}
cout << "调用了自定义的赋值构造函数" << endl;
this->name = people.name;
this->age = people.age;
strcpy_s(addr, 64, people.addr);
return *this;//方便连续的赋值 P1 = P2 = P3;
}
1.3 类的析构函数
作用:
对象销毁前,做清理工作。具体的清理工作,一般和构造函数对应比如:如果在构造函数中,使用new分配了内存,就需在析构函数中用delete释放。如果构造函数中没有申请资源(主要是内存资源),那么很少使用析构函数。
函数名:
~类型 没有返回值,没有参数,最多只能有一个析构函数
访问权限:
一般都使用public
使用方法:
不能主动调用。
对象销毁时,自动调用。
如果不定义,编译器会自动生成一个析构函数(什么也不做)
Person::~Person() {
cout << "调用了析构函数" << endl;
delete addr;
}
2.对象的基本使用
2.1 对象的定义
(1)类名 对象名
(2)类名 对象名(参数列表)
Person peo1;
Person peo2();//构造方法定义并初始化
2.2 对象调用方法
Person peo;
peo.printBasicInfo();
//通过指针调用
Person *p_peo;
p_peo->printBasicInfo();
3.类中的静态和const
3.1 类的静态数据成员
class Person{
private:
//类的静态数据成员,没有const修饰的静态变量,在定义时是不能初始化的
static int createCount;
}
/*
对于非const的类静态成员,只能在类的实现文件(类的定义放在头文件中,函数的实现放在.cpp文件中)中初始化。
const类静态成员,可以在类内设置初始值,也可以在类的实现文件中设置初始值。(但是不要同时在这两个地方初始化,初始化两次的话,以类外为准)
*/
int Person::createCount = 0;
3.2 类的静态成员函数
1. 可以直接通过类来访问【更常用】,也可以通过对象(实例)来访问。
2. 在类的静态方法中,不能访问普通数据成员和普通成员函数(对象的数据成员和成员函数)
3. 在类的静态成员函数中是不能使用this指针的。
class Person{
public:
static int getCount();
private:
static int Count;
}
int Person::createCount = 0;
//不要加static
int Person::getCount(){
// 静态方法中,不能访问实例成员(普通的数据成员)
// cout << age;
// 静态方法中,不能访问this指针
// 因为this指针是属于实例对象的
// cout << this;
//静态方法中,只能访问静态数据成员;
//但实例成员可以访问静态成员
return createCount ;
}
//调用:
cout << Person::getCount();
3.3 类中的 const 数据成员
const数据成员的初始化方式:
(1) 使用类内值(C++11支持)
(2) 使用构造函数的初始化列表
(如果同时使用这两种方式,以初始化列表中的值为最终初始化结果)
注意: 不能在构造函数或其他成员函数内,对const成员赋值!
class Person{
public:
Person();
Person(string name, int age, const char *addr,string bldType);
//...
private:
const string bloodType = "未知"; //类内值
}
Person::Person():bloodType("未知") { //1.初始化列表初始bloodType
cout << "调用了自定义的默认构造函数" << endl;
name = "未命名";
age = 0;
addr = new char[64];
strcpy_s(addr, 64, "China");
createCount++;
}
Person::Person(string name, int age, const char *addr ,string bldType):bloodType(bldType) { //2.初始化列表初始bloodType
cout << "调用了自定义的构造函数" << endl;
this->name = name;
this->age = age;
this->addr = new char[64];
strcpy_s(this->addr, 64, addr);
createCount++;
}
//
3.4 const 成员函数
(1)const成员函数不能修改类内变量的值
(2)const类型的对象只能调用const成员函数(构造函数、析构函数除外)
class Person{
public:
void printBasicInfo() const{
cout << this->name << endl;
cout << this->age << endl;
cout << this->addr << endl;
cout << this->bloodType << endl;
};
private:
//...
}
const Person peo1;
peo1.printBasicInfo();