C++基础知识补充

c++中创建对象不需要用new

比如Cube c1;

此时就声明了一个Cube对象

c++中,this关键字是指指向当前对象的指针

#include <iostream>
using namespace std;
 
class Student{
public:
    void setname(char *name);
    void setage(int age);
    void setscore(float score);
    void show();
private:
    char *name;
    int age;
    float score;
};
 
void Student::setname(char *name){
    this->name = name;
}
void Student::setage(int age){
    this->age = age;
}
void Student::setscore(float score){
    this->score = score;
}
void Student::show(){
    cout<<this->name<<"的年龄是"<<this->age<<",成绩是"<<this->score<<endl;
}
 
int main(){
    Student *pstu = new Student;
    pstu -> setname("李华");
    pstu -> setage(16);
    pstu -> setscore(96.5);
    pstu -> show();
 
    return 0;
}

如果获取了一个对象指针,那么可以用该对象->成员变量来使用该成员变量,该对象->方法来调用其方法

如果获取了一个对象引用,那么可以用该对象.成员变量来使用成员变量,或者该对象.方法来调用其方法

函数中既可以传形参,也可以传指针,也可以传引用

传引用的话,基础数据类型,和平时的用法一样,对于对象来说,用点.来调用其方法和变量

传指针的话,基础数据类型,需要解引用,对于对象来说,需要用->来调用其方法和变量

#include <iostream>
using namespace std;
#include <string>

//点类
class Point
{
public:
    //设置X坐标
    void setX(int x)
    {
        m_x = x;
    }
    //获取X坐标
    int getX()
    {
        return m_x;
    }
    //设置Y坐标
    void setY(int y)
    {
        m_y = y;
    }
    //获取Y坐标
    int getY()
    {
        return m_y;
    }


private:
    int m_x;
    int m_y;
};


//设置一个圆类Circle
class Circle
{
public:
    //设置半径
    void setR(int r)
    {
        m_R = r;
    }
    //获取半径
    int getR()
    {
        return m_R;
    }
    //设置圆心
    void setCenter(Point center)
    {
        m_center = center;
    }
    //获取圆心
    Point getCenter()    //m_center是Piont类的数据
    {
        return m_center;
    }


private:
    int m_R;
    //在类中可以让另一个类 作为本类中的成员--与结构体相似
    Point m_center;
};


//判断点和圆的关系
void isInCircle(Circle& c, Point& p)
{
    if ((p.getX() - c.getCenter().getX()) * (p.getX() - c.getCenter().getX()) + (p.getY() - c.getCenter().getY()) * (p.getY() - c.getCenter().getY()) == c.getR() * c.getR())
        cout << "点在圆上" << endl;
    else if ((p.getX() - c.getCenter().getX()) * (p.getX() - c.getCenter().getX()) + (p.getY() - c.getCenter().getY()) * (p.getY() - c.getCenter().getY()) > c.getR() * c.getR())
        cout << "点在圆外" << endl;
    else
        cout << "点在圆内" << endl;
}

int main()
{
    //创建并设置点P1
    Point P1;
    P1.setX(10);
    P1.setY(9);

    //创建并设置点P2--圆心
    Point P2;
    P2.setX(10);
    P2.setY(0);

    //设置圆C1
    Circle C1;
    C1.setR(10);
    C1.setCenter(P2);

    isInCircle(C1, P1);

    system("pause");
    return 0;

}

构造函数和析构函数

如果我们不写构造函数和析构函数,那么编译器会给我们提供构造函数和析构函数,但是编译器的构造函数和析构函数是空实现

构造函数和析构函数,构造函数是当对象实例化的时候调用的

析构函数是是对象销毁时自动调用,而且只会调用一次

构造函数和析构函数都是没有返回值的

构造函数和析构函数的函数名都是类名 比如构造函数是Person(),析构函数是~Person()

在main函数中,对象是放在堆区的,需要我们手动释放

按参数分为,构造函数中有无参构造和有参构造

按类型分为,构造函数中有普通构造和拷贝构造

拷贝构造函数,拷贝构造函数是将另一个对象的属性全部拷贝到自己身上

拷贝构造函数就是把另一个对象原封不动的赋值给自己

class MyClass {
public:
    int data;
 
    // 默认构造函数
    MyClass() {
        data = 0;
    }
 
    // 拷贝构造函数
    MyClass(const MyClass& other) {
    //不能修改另一个类,所以用const
        data = other.data;
    }
};

c++中,对象实例化,一般不用new,记住

Person p1;//默认构造,不要加括号,如果加了括号,编译器会认为是函数声明,比如Person p1(),编译器会认为这是一个函数

Person p2(10);//有参构造

Person p3(p2);//拷贝构造

在C++中,new和malloc都是用指针来接收的,如Person *p1=new Person();

java中没有析构函数,java中有一个GC垃圾回收器,而C++中,所有的堆区内存都需要我们手动释放

在java中,没有指针,所有都是引用,所有对象的方法和属性都可以用点.来调用

当我们用delete来销毁对象时,会直接调用析构函数,从而清除对象


//此时声明了一个匿名对象,当程序结束后,系统会立即回收匿名对象
Person(10)


Person p1;
Person p2=Person(10);
//不用new,这点跟java不同
Person p3=Person(p2);

java里只有两种构造函数,无参构造和有参构造,没有什么拷贝构造

对于普通类型,用delete来释放,对于数组类型,用delete[] 来释放,如delete[] arr

代码举例二:有new和delete
#include<iostream>
using namespace std;
class A
{
	public:
		A()
		{
			cout<<"构造函数"<<endl; 
		}
		~A()
		{
			cout<<"析构函数"<<endl; 
		 } 
 };
 int main()
 {
 	A a;//创建了A的对象a,调用无参的构造函数,输出第一行的“构造函数” 
 	A * p; 
 	p=new A();//new A在堆中分配对象,同时调用无参的构造函数, 输出第二行的“构造函数”
 	delete p;//删除p指向的空间,也就是释放这个对象,必然要调用析构函数,输出第三行的“析构函数” 
 	cout<<"end of main"<<endl;
 	return 0;
 }

比如A函数,B函数中有某一个功能

有一个C函数,需要调用A函数,或者B函数,那么此时就可以用函数指针的形式

#include <iostream>
#include <string>

using namespace std;

string base {"hello world"};

string append(string s)
{
    return base.append(" ").append(s);
}

string prepend(string s)
{
    return s.append(" ").append(base);
}

string combine(string s, string(*g)(string a))
{
    return (*g)(s);
}

int main()
{
    cout << combine("from MSVC", append) << "\n";
    cout << combine("Good morning and", prepend) << "\n";
}

C++的构造函数分为三类:有参,无参,拷贝

C++中有三种编译器提供的构造函数和析构函数:

1.默认无参构造函数(空实现)

2.默认析构函数(空实现)

3.默认拷贝构造函数

如果已经定义了有参构造,那么编译器就不会再提供无参构造,但是会提供拷贝构造

如果用户定义拷贝构造函数,那么默认的有参,无参都没有了

数据类型分为基本数据类型和引用数据类型

深拷贝和浅拷贝的区别:

深拷贝和浅拷贝的区别就是对于堆区分配的数据,深拷贝会新申请一片空间,然后拷贝这些值

浅拷贝只会拷贝这个引用的地址

默认的拷贝构造函数都是浅拷贝

一般对于对象,都是用new和delete,malloc和free是C语言中的用法,C语言没有面向对象的概念,C++中有面向对象的概念,当使用new时,会调用构造函数,当使用delete时,会调用析构函数

#include <iostream>
#include <string>
using namespace std;
 
class Cperson
{
public:
	Cperson()
	{
		pp = new int;
		cout << "Beginning" << endl;
	}
 
	~Cperson()
	{
		delete pp;
		cout << "End" << endl;
	}
 
private:
	int *pp;
};
 
int main()
{
	Cperson *op1 = (Cperson *)malloc(sizeof(Cperson));
	free(op1);
 
	Cperson *op2 = new Cperson;
	delete op2;
 
	system("pause");
	return 0;
}

这个对象里,堆区的内容都要用析构函数释放,也就是所有的指针型数据类型

浅拷贝会带来一个问题,如果Person p1对象中有a*指针变量,Person p2(p1),如果采用默认拷贝构造函数,那么会把a*指针变量浅拷贝一遍,如果执行析构函数,对p1和p2均进行释放,由于指向了同一片内存空间,可能会出现double free这种现象

如果对象中有堆区的空间,也就是指针型空间,那么必须自己提供拷贝构造函数

全部评论

相关推荐

08-15 22:24
门头沟学院 Java
我已成为0offer的糕手:你问问他要不要出来和你一起找工作
点赞 评论 收藏
分享
1 5 评论
分享
牛客网
牛客企业服务