带参数的构造函数
#include <iostream> using namespace std; class Triangle{ private: int a; int b; int c; public: ~Triangle(); Triangle(int a,int b,int c); void show(); bool check(); }; void Triangle::show(){ cout << "a=" << a << ",b=" <<b << ",c=" << c <<endl; } bool Triangle::check(){ return a+ b > c; } //构造函数没有void,int之类的修饰符 //如果方法参数与类变量重名,可以使用this区分 Triangle::Triangle(int a,int b,int c){ this->a =a; this->b =b; this->c =c; cout << "带参数构造函数生成具体的对象" << endl; } //自动被调用 Triangle::~Triangle(){ cout << "对象占用空间被销毁" << endl; } int main () { Triangle t1 = Triangle(3,4,5); t1.show(); cout << "是否为三角形:" << t1.check() << endl; return 0; }
$ g++ c.cpp $ ./a.out 带参数构造函数生成具体的对象 a=3,b=4,c=5 是否为三角形:1 对象占用空间被销毁
C++中的new和直接定义对象有以下主要区别
内存分配和释放: 使用new创建的对象需要手动释放,否则会导致内存泄漏。 而直接定义的对象在超出其作用域时会自动释放。 生命周期: 使用new创建的对象的生命周期可以手动控制,可以将其保留并在程序的其他部分使用。 而直接定义的对象的生命周期受局部作用域的限制。 存储位置: 使用new创建的对象存储在堆上,它们的生存期可以超出创建它们的作用域。 而直接定义的对象存储在栈上,它们在超出定义它们的作用域时会被自动销毁。 访问方式: 使用new创建的对象需要通过指针来访问和操作。 而直接定义的对象可以直接使用对象名称来访问和操作。 效率问题: 直接定义效率更高,频繁调用的场合并不适合new,总要去申请释放内存系统开销更大。 作用范围: new出来的对象指针可以在方法之间传递,并且这个对象指针所指向的堆中的对象实例仍然存在, 直接声明的对象是局部的,出了方法就没有了。 需要注意的问题: 使用new创建对象时,应该在不再需要该对象时手动释放其内存,以避免内存泄漏。 同时,使用delete释放后,也需要小心避免再次访问已释放的对象指针
#include <cstdio> //可以调用C中的printf #include <iostream> using namespace std; class A { public: void print(){ } }; int main() { A a = A(); a.print(); A* b = new A(); (*b).print(); b->print(); A& c = *b;//别名 c.print(); printf("a value=%p\n",&a); //a value=0x7ffe4810fab7 printf("b addr=%p\n",&b); //b addr=0x7ffe4810fab8 printf("b value=%p\n",b); //b value=0x55f6813852b0 printf("c void*=%p\n",&c); //c void*=0x55f6813852b0 delete b; return 0; }
变量的角度: a,b都是一个变量, c是一个引用,实为void*,类似于多态,本身无类型,关键看指向/引用 的是何类型 指针/地址的角度: a是普通变量,分配在栈上, &a就是变量a在栈上的地址,a的值指对象本身 当a是普通变量时,a直接指代值本身,即a可指代对象 一如int a= 3;一样,a可指代3这个数 b是指针变量,分配在栈上, &b就是变量b在栈上的地址,b的值指对象地址,非本身, (*b)才是对象本身 A&表示这是A类型对象的一个引用/别名,是引用类型,一个类型 因此c是对象本身,&c则是对象地址
这里本人还有一个小小的疑问, 变量分配在栈上,栈在虚拟内存的高位, new分配的地址在堆上,堆在虚拟内存的低位, 这没问题 有问题的是,栈是自高而低使用内存的, 但这里栈内存的分配却出现了自低而高的现象, 本人首次遇到这种现象,特此记录一下
类与对象
《C++ Primer》 C++通过类创建对象,对象中占空间的主要就是变量,比如int,float,double,char,char*等 还有计算这些变量的方法
构造函数
构造函数就是个函数,它唯一特殊的地方在于它执行的时机: 在类创建对象时自动执行 利用这一点,通常做一些变量初始化工作, 当然了,你想写点逻辑处理也没啥语法上问题...
#include <cstdio> //可以调用C中的printf #include <iostream> using namespace std; class A{ private: int aa,bb; public: A(int a,int b); int add(){ return aa+bb; } }; A::A(int a,int b):aa(a),bb(b){} int main() { A* a = new A(1,2); printf("%d\n",a->add()); return 0; }
简化构造函数的赋值操作
A::A(int a,int b):aa(a),bb(b){} 等价于 A::A(int a,int b){ this->aa = a; this->bb = b; }
析构函数执行的时机:对象生命周期结束时
析构函数是在对象消亡时,自动被调用,用来释放对象占用的空间。 有四种方式会调用析构函数: 1.生命周期:对象生命周期结束,会调用析构函数 2.delete:调用delete,会删除指针类对象 3.包含关系:对象Dog是对象Person的成员,Person的析构函数被调用时,对象Dog的析构函数也被调用。 4.继承关系:当Person是Student的父类,调用Student的析构函数,会调用Person的析构函数
析构函数自动被调用 如果对象中使用new分配了空间,则需要显式在析构函数中使用delete删除
引用的析构函数调用
#include <cstdio> //可以调用C中的printf #include <iostream> using namespace std; class A { private: int *a; public : A(){ a = new int; *a = 5; } ~A() { delete a; } int get() { return *a; } }; int main() { A* b = new A(); A& b1 = *b; A& b2 = *b; printf("b1 addr=%p\n",&b1); printf("b2 addr=%p\n",&b2); // delete &b1; //这一步执行,后面会直接卡死 cout << (*b).get() << endl; cout << b1.get() << endl; return 0; }
C++11:论构对象的构建和释放 C++ 析构函数何时被调用? 变量被析构函数释放的时候的注意事项