带参数的构造函数
#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++ 析构函数何时被调用?
变量被析构函数释放的时候的注意事项