C++ 知识点记载

声明:内容为转载   拼接 整理 而成  但是绝对的干货

 

一、预备知识—程序的内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序

这是一个前辈写的,非常详细

//main.cpp
int a = 0; //全局初始化区
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main() {
    int b; //栈
    char s[] = "abc"; //栈
    char *p2; //栈
    char *p3 = "123456"; //123456\0在常量区,p3在栈上。
    static int c = 0; //全局(静态)初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);
    //分配得来得10和20字节的区域就在堆区。
    strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

//p1和p2是存储在栈区的指针  但是其指向分配在堆区的那些内存空间的首地址 

问题1:  在构造函数中可以使用this吗?

              这个问题是不能,但是在百度的时候貌似存在一些特殊情况 好像能用,但是对于新手来说,不要在构造函数中使用。

原因是: 首先来看构造函数的作用:给创建的对象建立一个标识符; 为对象数据成员开辟内存空间; 完成对象数据成员的初始化。

只有当构造函数完成后,这个对象才是真正有效的,即this才是正确的。而再构造中使用this时,这个对象并没有完全的初始化好,所以存在问题。

 

问题2:在析构函数中使用delete的问题,大家看下面一段程序 。程序运行的环境的是vs2015   问题就出在析构函数中的delete

#include <iostream>
#include <windows.h>
#include <string.h>
using namespace std;
class person
{
public:
	person();
	person(char *nae, char sex, char *pi, int weight, int height) : name(nae), sex(sex),
		weight(weight), height(height) {strcpy_s(pid,pi);};//带参数的构造函数
	void change_data(char *name, char sex, char *pid, int weight, int height);//数据修改函数
	void walking(int k, int v);//以 v速度行走k步
	void hearing(char * sentence);//将句子中的字母小写变大写  大写变小写输出
	void speaking(int n);//说出整数num的英文句子
	void writeing();//在屏幕上画出汉字‘曲’
	void print();//输出人的属性
	void out(int a);//翻译小于1000的整数
	~person();//析构函数

private:
	char *name; //字符指针 本身存储在栈区 这个意思 就是要动态的申请堆区的存储空间 来存储人名 用这个指针指向申请的堆区的存储空间
	char sex;
	char pid[19];//身份证号码 18位 但是数组里面会有一个结束符  必须考虑哪一位的空间  定义为18个  会报错  在栈区 已经分配好了19个内存空间
	int weight;
	int height;

};

person::person()
{
	name = new  char[strlen("XXXXXX") + 1];
	name = "xxxx";
	//strcpy_s(name, "xxxxxx");
	sex = 'M';
	strcpy_s(pid,"xxxxxxxxxxxxxxxxxx");
	weight = 0;
	height = 0;
}
person::~person()
{
	if(name !=NULL)
		delete name;
}
void main()
{
	person  student("Tom", 'M', "372828199511071234", 100, 180);
	char *a = new char[strlen("13232")];
	delete a;
	int A;
}

对于这个问题真是把我折磨死了要。百度了两天,终于找到了可以使我信服的解释,ps:不保证这个答案正确  但是我理解着很爽。首先看完下面这两段话:

1:    析构是个流程性概念,delete是个操作概念。就是说你可以在任意流程里执行delete操作,而析构只能在流程逻辑中体现。举个例子,你吃饭的时候可以吃苹果,但不吃饭的时候你依然可以吃苹果,吃饭就是一个流程,吃苹果就是一个操作。

2:    一般逻辑,new的对象是独立的,所以要delete,但有些是依附于特定对象b的,所以当这个对象b被析构,会将依附对象同样析构掉(一些语言编译器会建立这样的关系,或做了析构流程处理)。

这里根据第二段话的理解,这里的name就是依赖于我们声明的对象的,在程序结束的时候 代码会自动调用析构函数。这是对象被析构,那么依附这个对象的成员也就同时被析构了,内存空间也就被释放了。所以在析构函数中如果再次使用delete name;这个语句来删除内从空间就相当于删除了两次,就不对。

ps:我还有疑问: 析构函数只能释放栈内的空间,可是new 申请的空间是在堆里啊 !   析构函数释放栈中对象的时候还能释放在堆中的对象成员的内存?  奶奶的不管了,在深究更迷糊了  ,就这样吧!有大佬看到可以给我解释一下 谢谢了。

 

这里还有一点需要注意:看上边第二段中后边说的那句话:(一些语言编译器会建立这样的关系,或做了析构流程处理)。但是不是所有的编译器都这样做了,我上面那个代码在vs2015中运行时崩溃的。因为我觉得vs2015就是做了这种析构流程处理。但是同样的代码我放在了 DEVC++编译器中进行运行 ,是没有问题的,说明DEVC++应该是没有做这种析构流程处理的。

下面这段小代码 是我找到了 ,可以很好的体会析构函数。大家可以自行运行一下

从输出结果可以知道:
对象是根据作用域范围而销毁的。而堆对象则需要显示调用delete关键字显示销毁。

#include <stdio.h>

class Test
{
	int mi;
public:
	Test(int i)
	{
		mi = i;
		printf("Test(): %d\n", mi);
	}
	~Test()
	{
		printf("~Test(): %d\n", mi);
	}
};

int main()
{
	Test t(1);

	Test* pt = new Test(2);

	delete pt;

	return 0;
}

 

问题3:父类指针可以直接指向子类对象,父类引用可以直接引用子类对象  这个问题的简单知识点

父子之间的赋值兼容问题:
当使用父类指针(引用)指向子类对象的时候
①子类对象退化为父类对象
②只能访问父类中定义的成员
③可以直接访问被子类覆盖的同名成员

父类子类指针函数调用注意事项
1,如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础类定义的函数(静态联翩)
2,如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很危险,也不符合生活习惯,在程序设计上也会给程序员带来困扰。(一般不会这么去定义)
3,如果基础类和衍生类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用那个函数要根据指针的原型来确定,而不是根据指针实际指向的对象类型确定。  如果有虚函数存在 那么 可以调用派生类的重写函数。

#include <iostream>
using namespace std;
class Base
{
public:
	void print() { cout << 'B'; }
};
class Derived : public Base
{
public:
	void print() { cout << 'D'; }
	void print1() { cout << 'A'; }
};
int main()
{
	Derived * pd = new Derived();
	Base * pb = pd;
	pb->print();
	//这种语句是不对的pb->print1();
	pd->print();
	delete pd;
	return 0;
}

 

 

 




 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值