C++类和对象2

简介: C++类和对象

C++类和对象1:https://developer.aliyun.com/article/1548154

4、构造函数调用规则

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

a、默认构造函数(无参、函数体为空);b、默认析构函数(无参、函数体为空);c、默认拷贝构造函数,对属性进行值拷贝;d、如果用户定义了有参构造函数,编译器会提供拷贝构造函数,不会提供无参构造函数;如果用户定义了拷贝构造函数,编译器不会提供无参构造函数。

#include <iostream>
 
using namespace std;
 
//构造函数的调用规则
//1、创建一个类,C++编译器会给每个类都添加至少3个函数;
//默认构造 (空实现)
//析构函数 (空实现)
//拷贝构造 (值拷贝)
class Person {
public:
    Person() {
        cout << "默认构造函数" << endl;
    }
 
    Person(int age) {
        cout << "有参构造函数" << endl;
        m_Age = age;
    }
//
//    Person(const Person &p) {
//        m_Age = p.m_Age;
//        cout << "拷贝构造函数" << endl;
//    }
 
    ~Person() {
        cout << "析构函数" << endl;
    }
 
    int m_Age;
};
 
void test01() {
    Person p;
    p.m_Age = 18;
    Person p2(p);
    cout << "p2的年龄为:" << p2.m_Age << endl;
}
 
int main() {
    test01();
    return 0;
 
 
}
 
 
默认构造函数
p2的年龄为:18
析构函数
析构函数

5、深拷贝与浅拷贝

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

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

浅拷贝,堆区的内存重复释放

#include <iostream>
 
using namespace std;
 
//深拷贝与浅拷贝
class Person {
public:
    Person() {
        cout << "Person的默认构造函数调用" << endl;
    }
 
    Person(int age, int hegith) {
        m_Age = age;
        m_Height = new int(hegith);//堆区
        cout << "Person的有参构造函数调用;" << endl;
    }
 
    Person(const Person &p) {
        cout << "执行拷贝构造函数" << endl;
        m_Age = p.m_Age;
//        执行深拷贝  浅拷贝代码:m_Height =p.m_Height
        m_Height = new int(*p.m_Height);
    }
 
    ~Person() {
//        析构代码,将堆区开辟数据做释放操作
        if (m_Height != NULL) {
//            浅拷贝,堆区的内存重复释放
            delete m_Height;
//            避免野指针出现
            m_Height = NULL;
        }
        cout << "析构函数" << endl;
    }
 
    int m_Age;//年龄
    int *m_Height;//身高
};
 
void test01() {
    Person p1(18, 160);
    cout << "p1的年龄为:" << p1.m_Age << " " << *p1.m_Height << endl;
    Person p2(p1);
    cout << "p2的年龄为:" << p2.m_Age << " " << *p2.m_Height << endl;
}
 
int main() {
    test01();
    return 0;
 
 
}
 
 

6 、初始化列表

作用:C++提供了初始化列表语法,用来初始化属性;

#include <iostream>
 
using namespace std;
 
class Person {
public:
//    初始化
//    Person(int a, int b, int c) {
//        m_A = a;
//        m_B = b;
//        m_C = c;
//    }
 
//初始化列表初始化属性
    Person(int a,int b,int c) : m_A(a), m_B(b), m_C(c) {
 
    }
 
    int m_A;
    int m_B;
    int m_C;
};
 
void test01() {
//    Person p1(1, 2, 3);
    Person p1(1,2,3);
    cout << p1.m_A << p1.m_B << p1.m_C << endl;
}
 
int main() {
//    初始化列表
    test01();
 
    return 0;
 
 
}
 
 

7、类对象作为类成员

当类中成员是其他类对象时,我们称该成员为对象成员,

构造顺序:先调用对象成员的构造,再调用本类构造,析构顺序相反.

#include <iostream>
 
using namespace std;
 
class Phone {
public:
    Phone() {
        cout << "Phone 的构造函数" << endl;
    }
 
    Phone(string name) : p_name(name) {
        cout << "Phone 有参的构造函数" << endl;
    }
 
    ~Phone() {
        cout << "Phone 的析构函数" << endl;
    };
    string p_name;
};
 
class Person {
public:
    Person() {
        cout << "Person 的构造函数" << endl;
    }
 
    Person(string name, string pName) : name(name), phone(pName) {
        cout << "Person 的有参构造函数" << endl;
    }
 
    ~Person() {
        cout << "Person 的析构函数" << endl;
    };
    string name;
//    对象成员
    Phone phone;
};
//当类中成员是其他类对象时,我们称该成员为对象成员,构造顺序:先调用对象成员的构造,再调用本类构造,析构顺序相反.
void test() {
    Person person("zhangsan","sanxing");
    cout<<person.phone.p_name<<endl;
}
 
int main() {
//    初始化列表
    test();
    return 0;
 
 
}
 
 
Phone 有参的构造函数
Person 的有参构造函数
sanxing
Person 的析构函数
Phone 的析构函数

8 、静态成员

静态成员就是在成员变量和成员函数前加上关键字static,成为静态成员。

静态成员变量:所有对象共享同一份数据,在编译阶段分配内存,类内申明,类外初始化;

静态成员函数:所有对象共享同一个函数,静态成员函数只能访问静态成员变量。

#include <iostream>
 
using namespace std;
 
//静态成员就是在成员变量和成员函数前加上关键字static,成为静态成员。
 
 
 
//静态成员变量
class Person {
public:
    //静态成员变量:所有对象共享同一份数据,在编译阶段分配内存,类内申明,类外初始化;
    static int m_A;
    int m_B;
 
//静态成员函数:所有对象共享同一个函数,静态成员函数只能访问静态成员变量。
    static void func() {
 
        cout << "static void func调用" << endl;
//        静态成员函数只能访问静态成员变量
        cout << m_A << endl;
    }
};
 
int Person::m_A = 100;
 
void test() {
    Person p;
    cout << p.m_A << endl;
    Person p2;
    p2.m_A = 200;
    cout << p.m_A << endl;
 
}
 
//静态成员变量
void test02() {
    Person p1;
//    1、通过对象进行访问
    cout << p1.m_A << endl;
//   2、通过类访问
    cout << Person::m_A << endl;
}
void test03(){
    Person::func();
}
int main() {
//    test();
//    test02();
    test03();
    return 0;
 
 
}
 
 
static void func调用
100

三、对象模型和this指针

1、成员变量与成员函数分开存储

空对象占用1个字节空间,非静态成员属于类的对象。

#include <iostream>
 
using namespace std;
 
//成员变量和成员函数分开存储
class Person {
public:
    int m_A; //非静态成员变量,属于类的对象
    static int m_B; //静态成员变量,不属于类的对象
    void func() {};//非静态成员函数,不属于类的对象
 
    static void funcs() {}; //静态成员函数,不属于类的对象
};
 
int Person::m_B = 100;
 
void test01() {
    Person p;
    //空对象占用内存空间为:1
    //C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
//    每个空对象都有独一无二的内存地址
    cout << "size of p=" << sizeof(p) << endl;
}
 
void test02() {
    Person p;
    cout << "size of p=" << sizeof(p) << endl;
}
 
int main() {
//    test01();
    test02();
    return 0;
 
 
}
 
 
size of p=4

2、this指针概念

this指针指向被调用的成员函数所属的对象。

this指针是隐含每一个非静态成员函数内的一种指针;

this指针不需要定义,直接使用即可;

用途:

当形参和成员变量同名时,可用this指针来区分;

在类的非静态成员函数中返回对象本身,可使用return *this;

#include <iostream>
 
using namespace std;
 
class Person {
public:
//    Person(int age) : age(age) {};
    Person(int age) {
//    this指针指向被调用的成员函数所属的对象。
        this->age = age;
    }
 
    Person &PersonAddAge(Person &p) {
        this->age += p.age;
        return *this;
    }
 
    int age;
};
 
//1 解决名称冲突
void test01() {
    Person p(18);
    cout << "年龄:" << p.age << endl;
}
 
//2 返回对象本身用*this
void test02() {
    Person p1(10);
    Person p2(20);
    cout << "年龄:" << p2.age << endl;
//    链式编程
    p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
    cout << "年龄:" << p2.age << endl;
}
 
int main() {
//    test01();
    test02();
    return 0;
}
 
 


年龄:20
年龄:60

3、空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针;

如果用到this指针,需要加以判断保证代码的健壮性;

#include <iostream>
 
using namespace std;
 
//C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针;
//如果用到this指针,需要加以判断保证代码的健壮性;
class Person {
public:
    void showClassName() {
        cout << "this is Person class" << endl;
    }
 
    void showPersonAge() {
//        防止空指针访问,导致程序崩溃
        if (this == NULL) {
            return;
        }
        cout << "年龄:" << this->m_Age << endl;
 
 
    }
 
    int m_Age;
};
 
void test01() {
    Person *p = NULL;
    p->showClassName();
    p->showPersonAge();
}
 
int main() {
    test01();
    return 0;
}
 
 
this is Person class

4、const修饰成员函数

常函数:成员函数后加const后我们称这个函数为常函数,常函数内不可以修改成员属性,成员属性声明时加关键字mutable后,在常函数中依然可以修改。

常对象:申明对象前加上const称该对象为常对象,常对象只能调用常函数。

#include <iostream>
 
using namespace std;
 
//常函数:成员函数后加const后我们称这个函数为常函数,常函数内不可以修改成员属性,成员属性声明时加关键字mutable后,在常函数中依然可以修改。
class Person {
public:
//    this指针的本质是指针常量,指针的指向是不可以修改的
//const Person * const this; 成员函数后边的const,本质是修改this指正
    void showPerson() const {
        cout << this->m_A << endl;
//        m_A=100; //常函数无法修改非mutable修饰的变量
        this->m_B = 1000;
    }
 
    void showNum() {
        cout << m_B << endl;
    }
 
    int m_A;
    mutable int m_B; //常函数中可以修改
};
 
//常对象:申明对象前加上const称该对象为常对象,常对象只能调用常函数。
void test01() {
//    常对象
    const Person p1{};
    p1.m_B = 200;
//    常对象只能调用常函数
    p1.showPerson();
//    p1.showNum(); //常对象不可以调用普通成员函数,因为普通成员函数可以修改属性
 
};
 
int main() {
    test01();
    return 0;
}
 
 

四、友元

友元:让一个函数或类,访问另一个类中私有成员;关键字为friend;

1、全局函数做友元

#include <iostream>
#include <string>
 
using namespace std;
 
//建筑物
class Building {
//    gooeGay函数是Building的好朋友,可以访问Building的私有属性
    friend void gooeGay(Building &build);
 
public:
    Building() {
        m_SittingRoom = "ke——ting";
        m_BedRoom = "wo-shi";
    }
 
public:
    string m_SittingRoom;//客厅
private:
    string m_BedRoom;//卧室
};
 
//全局函数
void gooeGay(Building &build) {
    cout << "public: " << build.m_SittingRoom << endl;
    cout << "private: " << build.m_BedRoom << endl;
}
 
void test01() {
    Building building;
    gooeGay(building);
}
 
int main() {
    test01();
    return 0;
}
 
 


public: ke——ting
private: wo-shi

2、类做友元

#include <iostream>
#include <string>
 
using namespace std;
 
class Building;
 
class GoodGay {
public:
    GoodGay();
 
public:
    void visit();
 
    Building *building;
};
 
 
class Building {
//    GoodGay是本类的好朋友,可以访问私有属性
    friend class GoodGay;
 
public:
    Building();
 
public:
    string m_SittingRoom; //客厅
private:
    string m_BedRoom;//卧室
};
 
Building::Building() {
    m_SittingRoom = "ke——ting";
    m_BedRoom = "wo-shi";
}
 
GoodGay::GoodGay() {
    building = new Building;
}
 
void GoodGay::visit() {
    cout << building->m_SittingRoom << endl;
    cout << building->m_BedRoom;
}
 
void test01() {
    GoodGay gay;
    gay.visit();
}
 
int main() {
    test01();
    return 0;
}
 
 

3、成员函数做友元

#include <iostream>
#include <string>
 
using namespace std;
 
class Building;
 
class GoodGay {
public:
    GoodGay();
 
public:
    void visit();
 
    void visit2();
 
    Building *building;
};
 
 
class Building {
//    GoodGay::visit()函数是本类的好朋友,可以访问私有属性
    friend void GoodGay::visit();
 
public:
    Building();
 
public:
    string m_SittingRoom; //客厅
private:
    string m_BedRoom;//卧室
};
 
Building::Building() {
    m_SittingRoom = "ke——ting";
    m_BedRoom = "wo-shi";
}
 
GoodGay::GoodGay() {
    building = new Building;
}
 
void GoodGay::visit() {
    cout << building->m_SittingRoom << endl;
    cout << building->m_BedRoom;
}
 
void GoodGay::visit2() {
    cout << building->m_SittingRoom << endl;
//    cout << building->m_BedRoom;
}
 
void test01() {
    GoodGay gay;
    gay.visit();
}
 
int main() {
    test01();
    return 0;
}
 
 

C++类和对象3:https://developer.aliyun.com/article/1548158?spm=a2c6h.13148508.setting.17.224d4f0e8YFWtB

相关文章
|
2天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
15 2
|
8天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
33 5
|
14天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
46 4
|
15天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
43 4
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
28 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
25 4
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)