c++一些操作

指针转化

#include<iostream>
using namespace std;
class node {
public:
    
    char c[1024];
    int length;

    node() {
        length = sizeof(node);
    }
};
int main() {
    node n;
    cin >> n.c;

    char* c = (char*)&n;	//将n的地址转换成char*,赋值给c
    cout << &n << endl; 
    cout << (int*) c << endl;//打印c指向的地址,可以看出与n的地址一样
    node *p = (node*)c;     //用一个node* 接收c的值 ,此时p就是指向n的指针
    cout << p->c << endl;  //打印字符串
    return 0;
}

输出结果:

hello
0133F798
0133F798
hello

1.如果给cout提供一个指针,它将打印指针所指向的地址单元的地址,但如果指针类型为char *,则cout将打印char *指针所指向的字符串。
2.如果要显示char *指针所指向的地址单元的地址,需要将char *类型的指针强制转化为另一种类型的指针,我将char *类型的指针强制转化为int *类型指针。

不定参数

int f(int a,...);

这样跟在a后面的三个点代表不定参数,意味着后面还可以跟多个参数。
后面的参数类型跟a一样。
暂时觉得没必要去深究底层栈那些。
看看怎么用。
stdarg.h提供了几个函数:
va_start(list,param1) ,获取可变参数列表的第一个参数的地址。
va_arg(list,mode),获取可变参数的当前参数。
va_end(list) , 清空va_list可变参数列表。

void MyPrintF( const char * format, ... )
{
 	int size = vsnprintf(NULL, 0, format, arg_ptr);
 	char* content = new char[size + 1];
	va_list args;
	va_start (args, format);
	vsnprintf(content, size + 1, format, arg_ptr);
	va_end (args);
 	cout<<content<<endl;
}
int main()
{	
	MyPrintF("my name is %s,my age is %d\n","bob",18);
    return 0;
}

这个片段一般用来打印日志。

sstream 类型转换

主要用来进行数据类型转换,相比 C 编程语言库的数据类型转换, 更加安全、自动和直接。
以下代码包含头文件:

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

题目1: 将(int)1000转化成字符串。

int main()
{
    stringstream sstream;
    string strResult;
    int nValue = 1000;

    sstream << nValue;
    sstream >> strResult;
    
    cout << strResult << endl;
    printf(" %s\n", strResult.c_str());
 
    return 0;
}

题目2:拼接多个字符串,输出,然后重新拼接多个字符串输出。


int main()
{
    stringstream sstream;

    sstream << "first" << " " << "string,";
    sstream << " second string";
    cout  << sstream.str() << endl;

    sstream.str("");
    sstream << "third string, ";
    sstream << "fourth string";
    cout  << sstream.str() << endl;


    return 0;
}

题目3:将(string)5546.16(double)5546.16类型输出,再将(string)1转化成bool类型输出。

int main()
{
    stringstream sstream;
   
    sstream << "5546.16";
    double w = 0;
    sstream >> w;
    cout << w << endl;
    cout  << sstream.str() << endl;

    sstream.clear();
    //sstream.str("");

    sstream << true;
    int e;
    sstream >> e;
    cout  << e << endl;

    return 0;
}

在本示例涉及的场景下(多次数据类型转换),必须使用 clear() 方法清空 stringstream,不使用 clear() 方法或使用 str(“”) 方法,都不能得到数据类型转换的正确结果。

文件操作

c++提供了三个文件操作流。

ofstream //写文件
ifstream //读文件
fstream  //读写文件

函数参数:

  • filename 要打开文件的文件名
  • mode 打开文件的方式
mode参数方式
in读的方式打开文件/ifstreamd的默认类型
out写的方式打开文件/ofstream的默认类型
app所有操作都定位到文件末尾
trunc打开的时候定位到文件末尾
ate打开的时候定位到文件末尾

题目1:将一串字符写入out.txt文件,然后再取出,再将一串字符写入到out.txt文件的数据末尾。

int main() {
    ofstream out("out.txt");
    if (out.is_open())
    {
        out << "This is a line.\n";
        out << "This is another line.\n";
      
        out.close();
    }
    
    ifstream in("out.txt");
    string buffer;

    while (getline(in, buffer))
    {
        cout << buffer << endl;
    }
   
    ofstream out("out.txt",ios::app);
    if (out.is_open())
    {
        out << "This is a line.\n";
        out << "This is another line.\n";

        out.close();
    }

    return 0;
}

上面代码向out流类输入了两个字符串,然后取出。
getline函数一行一行取出数据,直至取完,然后返回空。
ofstream out("out.txt",ios::app);将文件打开,定位到末尾,后面再输入数据就可追加到文件末尾。

多态

多态已经是耳熟能详的东西了,网上关于多态的解释教学数不胜数,但是我还是想简单说一下。

首先是c++实现多态必须要有virtual。

c++多态有两种表现形式:

  • 基类指针指向子类对象
  • 子类对象通过引用赋值给基类

第一种的形式是:

class Vehicle 
{     
public:
     virtual void run() 
     {
         cout << "开交通工具" << endl;
     };
    
};
class ride : public Vehicle
{
public:
    void run()
    {
        cout << "开自行车" << endl;
    }
};
class car:public Vehicle
{
public: 
    void run()
    {
        cout << "开汽车" << endl;
    }

};

int main() {
	//1
    Vehicle *c = new ride() ;
    c->run();
	delete(c);
	c = NULL;
 	//2
 	car s;
    Vehicle &o = s;
    o.run();
    return 0;
}
output:
开自行车
开汽车
值得注意的是,以上代码如果写成:
int main() {
    ride s;
    Vehicle c = s;
    c.run();
    return 0;
}
output:
开交通工具

这就不是多态。
这就与虚函数表有关。
顺带一提,通过new 得到的空间要记得释放,防止内存泄漏。释放之后将指针置为空,防止野指针。

虚函数表

class Vehicle 
{     
public:
      void run() 
     {
         cout << "开交通工具" << endl;
     };
    
};

int main() {
   
    cout << sizeof(Vehicle) << endl;
    return 0;
}
output:
1

从上面可以看出 class占用的内存空间为1;

class Vehicle 
{     
public:
     virtual void run() 
     {
         cout << "开交通工具" << endl;
     };
    
};

int main() {
   
    cout << sizeof(Vehicle) << endl;
    return 0;
}
output:
4

加了virtual后变成了4;

事实上当类中有虚函数时,编译器会生成一个虚函数表virtual table。同时生成一个指针void bptr指向表。虚函数表指向类的虚函数,来实现多态,这个虚函数表会一直伴随类;具体虚函数表怎么实现多态这里就不讲了 ,我也不会 。但是我想也没必要纠结这么细,毕竟底层已经做好了,我们也改不了。

虚析构

上面讲了多态的构造要使用虚函数,那么当我们想通过多态,也就是用父类指针销毁子类对象时,要怎么做?

析构函数是在删除对象或退出程序的时候,自动调用的函数,其目的是做一些资源释放。

那么在多态的情景下,通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数,这就会存在派生类对象的析构函数没有调用到,存在资源泄露的情况。

看这个例子:

class Vehicle
{
public:
    int a[10];
    Vehicle()
    {
        cout << "Vehicle构造" << endl;
    }
    ~Vehicle()
    {
        cout << "Vehicle析构" << endl;
    }

};
class ride : public Vehicle
{
public:
    ride()
    {
        cout << "ride构造" << endl;
    }
    ~ride()
    {
        cout << "ride析构" << endl;
    }
};

int main() {
    Vehicle * c = new ride();
    delete(c);
    c = NULL;
    return 0;
}
output:
Vehicle构造
ride构造
Vehicle析构

程序删除c的时候,没用调用子类的析构函数。
显然,销毁对象要调用析构函数,那么销毁对象就要将父类的析构设为虚析构。

将上述的代码中的父类的析构函数,定义成「虚析构函数」:

class Vehicle
{
public:

    Vehicle()
    {
        cout << "Vehicle构造" << endl;
    }
    virtual ~Vehicle()
    {
        cout << "Vehicle析构" << endl;
    }

};
class ride : public Vehicle
{
public:
    ride()
    {
        cout << "ride构造" << endl;
    }
    ~ride()
    {
        cout << "ride析构" << endl;
    }
};

int main() {
    Vehicle * c = new ride();
    delete(c);
    c = NULL;
    return 0;
}
output:
Vehicle构造
ride构造
ride析构
Vehicle析构
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值