C++知识点总结(面向对象6-隐式构造, 友元, 内部类, 局部类)

对象类型的参数和返回值

使用对象类型作为函数参数或者返回值, 可能会产生一些不必要的中间对象
(1)对象类型做函数参数时

void test1(Car car) { // 对象类型作为参数
	
}
int main() {
	Car car1;
	test1(car1);
}

把外面的对象传给里面的对象时, 会产生一个新的对象(不必要的中间对象), 因为相当于void test1(Car car = car1)利用一个已经存在的对象, 构建出了一个新的对象, 所以就是拷贝构造.
解决这个问题: 传引用或指针

void test1(Car &car) {

}
int main() {
	Car car1;
	test1(car1);
}

相当于void test1(Car &car = car1) 就直接引用着外面的car1对象, 这样就不会产生新的对象, 即将car1的地址值传给了car这个引用去保存, 因为引用的本质就是指针, 所以就是地址传递, 不会直接将对象传过去去构建一个新的对象.
(2)对象类型做返回值时:

Car test2() {
	Car car;
	return car;
}
int main() {
	Car car2;
	car2 = test2();
}

当把car返回时, 会多出一个拷贝构造, 因为在函数里面定义的car对象的内存在teat2所在的栈空间, 要把test2栈空间里面的对象返回到main函数的栈空间里, 而它的内存在离开函数后就销毁了, 所以要拷贝.
它的做法是:提前将test2里面的car对象拷贝构造出一个新的对象, 而这个新对象的内存是在main函数里面的.
(3)编译器优化

Car test2() {
	Car car;
	return car;
}
int main() {
	Car car3 = test2();
}

只会调用1次拷贝构造, 直接给car3

匿名对象(临时对象)

匿名对象:没有变量名, 没有被指针指向的对象, 用完马上调用析构
(1)编译器优化(了解)
匿名对象作为参数
(2)编译器优化(了解)
直接返回匿名对象

隐式构造

C++里面存在隐式构造的现象 : 某些情况下, 会隐式调用单参数的构造函数
(1)Person p1 = 20;
调用了单参数的构造函数, 等价于Person p1(20);
(2)

void test1(Person person) {

}
int main() {
	test1(20);
}

相当于Person person = 20; 调用单参数的构造函数构建对象
(3)

Person test2() {
	return 40;
}
int main() {
	test2();
}

隐式构造, 调用单参数构造函数构建出对象
(4)

Person p1;
p1 = 40;

只有对象才可以赋值给对象, 所以40会发生隐式构造, 相当于Person(40), 调用单参数的构造函数构建出一个临时对象.
(5)可以通过关键字explicit(明确的意思)来禁止掉隐式构造

class Person {
	int m_age;
public:
	explicit Person(int age) : m_age(age) {}
};

(6)有些地方也叫转换构造, 因为会将40直接转换成Person对象.

编译器自动生成的构造函数

C++的编译器在某些特定的情况下, 会给类自动生成无参的构造函数, 比如
(1)成员变量在声明的同时进行了初始化

class Person {
public:
	int m_price = 5;
}

等价于

class Person {
public:
	int m_price;
	Person() {
		m_price = 5;
	}
}

编译器会自动生成构造函数, 初始化是在构造函数中做的.
(2)有定义虚函数
因为一旦有虚函数的话, 这个对象会多出4个字节来存放虚表地址.
在创建完Person对象后, 要给Person对象的最前面的4个字节赋虚表地址.
在这里插入图片描述
vftable = virtual function table
(3)虚继承了其他类
class Student : virtual public Person {

}
一旦虚继承了某个类, 那么当时候某个类创建出来的对象最前面4个字节存储着虚表地址
(4)包含了对象类型的成员, 而且这个成员有构造函数(自定义或编译器生成)

class Car {
public:
	int m_price;
	Car() {}	
};
class Person {
	Car car;
}
int main() {
	Person person;
}

创建完person对象之后, person对象里面要搞一个Car对象, 就要调用Car的无参的构造函数,
所以这个时候编译器就会为Person这个类生成一个构造函数, 在构造函数里面调用Car的 构造函数去初始化car
(5)父类有构造函数(编译器生成或自定义)

class Person {
public:
	Person() {}
};
class Student : public Person {
public:
};

因为子类要优先调用父类的构造函数, 所以编译器会为子类自动生成构造函数, 在构造函数里调用父类的构造函数.
总结:对象创建后, 需要做一些额外操作时(比如内存操作(为成员变量赋值), 函数调用), 编译器一般都会为其生成无参的构造函数.

友元

友元函数包括友元函数和友元类
(1)如果将函数A(非成员函数)声明为类C的友元函数, 那么在函数A内部就能直接访问类C对象的所有成员.

class Point {
	friend Point add(Point, Point);
}

(2)如果将类A声明为类C的友元类, 那么在类A的所有成员函数内部都能直接访问类C对象的所有成员.
friend class [类名];

内部类

如果将类A定义在类C的内部, 那么类A就是一个内部类(嵌套类)
内部类的特点:
(1)支持public, protected, private 权限

class Person {
public:
	class Car {
		int m_price;
	};
};
int main() {
	Person::Car car1;
	// 创建了一个car对象
}

(2)内部类的成员函数可以直接访问其外部类对象的所有成员(反过来则不行)
(3)成员函数可以直接不带类名, 不带对象名访问其外部类的static成员

class Point {
private:
    static void test1() {
        cout << "Point::test1()" << endl;
    }
    static int ms_test2;
    int m_x;
    int m_y;
public:
    class Math {
    public:
        void test3() {
            cout << "Point::Math" << endl;
            test1();
            ms_test2 = 10;

            Point point;
            point.m_x = 10;
            point.m_y = 20;
        }
    };
};

(4)不会影响外部类的内存布局, 仅仅是访问权限变了而已, 内存布局是不变的.(编译器特性)
(5)可以在外部类内部声明, 在外部类外面定义.

局部类

在一个函数内部定义的类称之为局部类.
局部类的特点:
(1)作用域仅限于所在的函数内部
(2)其所有的成员必须定义(声明和实现)在类内部, 不允许定义static成员变量
因为static成员变量时使用前必须放在类外面初始化, 而局部类又要求必须放在里面, 矛盾.
(3)成员函数不能直接访问函数的局部变量(static变量除外)
因为函数的局部变量, 只有在调用函数时才分配存储空间, 那么在调用对象的成员函数访问其外部函数的局部变量时, 该局部变量还没有分配存储空间, 所以报错
在成员函数的栈空间里不能访问其他的栈空间里面的变量.
(4)局部类不影响其外部函数的内存布局.因为类的定义是代码, 存放在代码段, 不会开辟栈空间, 只有在创建对象时, 才会开辟栈空间(前提对象里面有成员变量). 类的定义和执行函数不同.
类放在函数里面或外面仅仅是访问权限的变化.


其他C++系列文章:

C++知识点总结(基础语法1-函数重载, 默认参数)
C++知识点总结(基础语法2-内联函数, const, 引用)
C++知识点总结(面向对象1-类和对象, this指针, 内存布局)
C++知识点总结(面向对象2-构造函数, 初始化列表)

C++知识点总结(面向对象3-多态)

C++知识点总结(面向对象4-多继承, 静态成员static)
C++知识点总结(面向对象5-const成员, 拷贝构造函数)
C++知识点总结(面向对象6-隐式构造, 友元, 内部类, 局部类)
C++知识点总结(其他语法1-运算符重载)
C++知识点总结(其他语法2-模板, 类型转换, C++11新特性)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值