c++的studylog

今天在看c++的视频学习的时候,有个问题很不解

  代码如下:

   

#include <iostream>
using namespace std;
class A{
    public:
      A(int i){ cout<<"执行构造函数!\n";x=i;}
      A(A&a){ cout<<"执行复制构造函数!\n";}
      ~A(){cout<<"析构函数!";}
      int get(){ return x;}
    private:
      int x;
};

A func(){
    cout<<"跳转!"<<endl;
    A a(34);
    cout<<"对象a的地址:"<<&a<<endl;
    return a;

}
int main(){
     A &r=func();
    cout<<"对象a的副本地址:"<<&r<<endl;
    cout<<r.get()<<endl;
    return 0;
}

第21行代码编译报错:

|error: invalid initialization of non-const reference of type 'A&' from a temporary of type 'A'|
||=== Build finished: 1 errors, 0 warnings ===|

但是学习的视频代码没有错误,代码编译正常。

但在这行代码之前加个 const就可以通过编译。

即:const A &r=func(); //临时对象是const的



很不解的是视频上的是a的地址和a的副本地址不一样,即a的副本对象是调用构造函数创建的对象a的一个副本,也就是 说 两个对象不是一样的对象。

但是我在编译这段代码的时候,a和a的副本地址是一样的,析构函数也是输出一次。


注解:

函数返回一个对象值时,会产生临时对象,函数中的返回值会以值拷贝的形式拷贝到被调函数栈中的一个临时对象。

栈中对象都是系统自动分配的,堆中对象是delete删除的。


常量和引用只能初始化,不能赋值;


构造函数的初始化:

class rectangle{
   public:
       rectangle(int a,int b):length(a),total(b){}
    private:
       const int length;
       int &total;
};

#include <iostream>
using namespace std;

class A{
   public:
       A(){}
       //A(A&one){n=one.n;m=one.m;}
       A(int a,int b){m=a;n=b;}
       void print(){
          cout<<n<<m;
       }
    private:
       int m;
       int n;
};
int main(){
   A a(2,4);
   a.print();
   cout<<"\n";
   A &c=a;
   A b(c); //完成两个对象之间成员的拷贝。即 c拷贝到b
   b.print();

    return 0;
}


2013-06-02:

#include "mvk.h"
using namespace std;

class A{
   public:
       A(){ x=new int;*x=5;}
       ~A(){ delete x;x=NULL;}
       void print() const{
          cout<<*x<<endl;
       }
       void set(int i){*x=i;}

    private:
       int *x;
};
int main(){
    A *a=new A();
    cout<<"a:"<<endl;
    a->print();

    cout<<"b:"<<endl;
    A b(*a);//这里两个对象的复制,可以写成:A b=*a; A*b=a;

    b.print();

    return 0;
}

由于a和b都指向同一块内存堆,当delete a后,a指向的堆删除了,b指针指向的内存区域也就不存在了,这时程序会报错。


2013-07-24

刚学c++的时候,对指针的表现方式很模糊,有时会产生矛盾的理解,比如说举个简单的例子来说:


#include <iostream>
using namespace std;

void reset(int *p){
   *p=0;

}
int main (int argc ,const char *argv[]){
    cout<<"begin:"<<endl;
    int i=32;
    int *p= &i;
    cout<<"p的地址:"<<p<<endl;

    reset(p);
    p=0;
     cout<<"p的地址:"<<p<<endl;

}

reset函数的参数int  *p是个指针,调用的时候reset(p),有时候会这样理解why调用的reset不是reset(*p)呢(当然reset(*p)的调用方式是错误的),

而是reset(p)呢,其实可以这样理解,reset函数参数int   *p可以写成int*   p,int*是一种整型指针类型,p是变量名,即指针。


2013-07-25


 

typedef char* pStr;


char string[4] = "abc";


 const char* p1 = string;// char* const p1=string;


const pStr p2 = string;


p1++; //这个是对的,如果换成注释的,那就不可以了。


p2++;//error

const pStr p2和const int x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。



函数指针的用法:

代码【1】

代码【1】
#include <iostream>
using namespace std;
int  Max(int a, int b)
{
    return a > b ? a : b;
}


typedef int (*pFun)(int, int);
pFun max_=&Max;//或者pFun max_=Max;


int main(int argc ,const char* argv[]){
    int a = 3;
    int b = 4;

    cout<<"Test function pointer: "<<endl;
    cout<<(*max_)(a,b)<<endl;//或者cout<<(max_)(a,b)<<endl;
  
}


代码【2】

#include <iostream>
using namespace std;

int  Max(int a, int b)
{
    return a > b ? a : b;
}

int  Min(int a, int b)
{
    return a < b ? a : b;
}

/*通用接口函数,实现对其他函数的封装*/
int   Result(pFun fun, int a, int b)
{
    return (*fun)(a, b);//(fun)(a,b)也可以
}

int main(int argc ,const char* argv[]){
    int a = 3;
    int b = 4;
    cout<<"Test function pointer: "<<endl;
    cout<<"The maximum number between a and b is "<<Result(Max, a, b)<<endl;
    cout<<"The minimum number between a and b is "<<Result(Min, a, b)<<endl;
}

1)  函数指针的初始化

函数如下:

1  int CompareString( const  string& str1,  const  string& str2)
2 {
3      return str1.compare(str2);  

4 }

函数的初始化有两种方式:

第一种,也是最普遍的方式:

1  int (*CompareFunction)( const  string&,  const  string&) = CompareString;

第二种,是使用typedef定义函数类型,这种写法有助于对代码的理解:

1  typedef  int (*CompareFunctionType)( const  string&,  const  string&);
2 CompareFunctionType CompareFunction = CompareString;

2)  函数指针赋值。

函数名可以理解为该类型函数的指针。当然,取地址操作符作用于函数名上也能产生指向该类型函数的指针。也就是说下面两种赋值都是可行的:

1 CompareFunctionType CompareFunction = CompareString;
2 CompareFunctionType CompareFunction =  &CompareString;

3)  函数调用。

无论是用函数名调用,还是用函数指针调用,还是用显式的指针符号调用,其写法是一样的:

1 CompareString( " abc "" cba ");
2 CompareFunction( " abc "" cba ");
3  (*CompareFunction)( " abc " " cba " );


参考:http://www.cnblogs.com/AnnieKim/archive/2011/11/20/2255813.html


代码【3】

#include <iostream>

using namespace std;

class Base {
     public:
            virtual void f() { cout << "Base::f" << endl; }
            virtual void g() { cout << "Base::g" << endl; }
            virtual void h() { cout << "Base::h" << endl; }

};



int main (int argc ,const char *argv[]){

   typedef void(*Fun)(void);

            Base b;

            Fun pFun = NULL;

            cout<<&b<<endl;
            cout<<(int*)*((int*)(&b))<<endl;
            cout << "虚函数表地址:" << (int*)(&b) << endl;
            cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;

            // Invoke the first virtual function
            pFun = (Fun)*((int*)*(int*)(&b));//不理解(Fun)*的含义
            pFun();

}
函数指针参考: http://blog.jobbole.com/44639/

内容概要:本文深入探讨了多种高级格兰杰因果检验方法,包括非线性格兰杰因果检验、分位数格兰杰因果检验、混频格兰杰因果检验以及频域因果检验。每种方法都有其独特之处,适用于不同类型的时间序列数据。非线性格兰杰因果检验分为非参数方法、双变量和多元检验,能够在不假设数据分布的情况下处理复杂的关系。分位数格兰杰因果检验则关注不同分位数下的因果关系,尤其适合经济数据的研究。混频格兰杰因果检验解决了不同频率数据之间的因果关系分析问题,而频域因果检验则专注于不同频率成分下的因果关系。文中还提供了具体的Python和R代码示例,帮助读者理解和应用这些方法。 适合人群:从事时间序列分析、经济学、金融学等领域研究的专业人士,尤其是对非线性因果关系感兴趣的学者和技术人员。 使用场景及目标:①研究复杂非线性时间序列数据中的因果关系;②分析不同分位数下的经济变量因果关系;③处理不同频率数据的因果关系;④识别特定频率成分下的因果关系。通过这些方法,研究人员可以获得更全面、细致的因果关系洞察。 阅读建议:由于涉及较多数学公式和编程代码,建议读者具备一定的统计学和编程基础,特别是对时间序列分析有一定了解。同时,建议结合具体案例进行实践操作,以便更好地掌握这些方法的实际应用。
### 如何在 C++ 中引用外部文件 在 C++ 编程中,`#include` 是一种常见的机制,用于将一个文件的内容嵌入到另一个文件中。这种技术广泛应用于头文件(`.h` 或 `.hpp` 文件)和源文件(`.cpp` 文件)。以下是关于 `#include` 的详细介绍以及其使用方法。 #### 头文件的作用 头文件通常用来声明函数原型、类定义以及其他全局变量或常量。它们的主要目的是提供接口供其他模块调用实现细节而不暴露具体逻辑。例如,在给定的例子中: ```cpp #ifndef COMMON_H #define COMMON_H #include <iostream> #include <string> void foo(); #endif // COMMON_H ``` 这段代码展示了如何防止重复包含同一头文件而导致的多重定义错误[^1]。宏保护符 (`#ifndef`, `#define`, 和 `#endif`) 被称为 **头卫士** (header guards),确保即使多次包含该头文件也不会引发冲突。 #### 源文件中的实现 对应的源文件则负责实际的功能实现部分: ```cpp #include "common.h" void foo() { std::cout << "Hello, world!" << std::endl; } ``` 这里通过 `#include "common.h"` 将头文件内容引入当前源文件,从而允许访问其中声明的对象和功能。 #### 解决循环依赖问题 当两个头文件互相引用时可能会遇到编译失败的情况。比如如下场景会触发此类问题: ```cpp // A.h #include "B.h" class A {}; // B.h #include "A.h" class B {}; ``` 上述情况会导致无限递归包含并最终崩溃。为了避免这种情况发生,可以通过前向声明或者调整设计来消除不必要的双向关联[^2]: - 前向声明仅需知道类型的名称而无需完整的定义即可工作; - 修改架构减少直接交互频率也是可行方案之一。 #### 引入特定平台库 有时项目可能还需要加载某些操作系统特有的APIs或者其他第三方资源管理器等复杂组件。这时就需要额外指定这些特殊需求所在位置路径信息以便链接器能找到他们。像这样一段来自Windows环境下的配置读取例子说明了这一点: ```cpp #include <iostream> #include <string.h> #include <windows.h> using namespace std; #define INI_FILE_PATH "./study.ini" #define LOG_VALUE_MAXSIZE 80 void readIniFile(char* lable, char* anchor, char*& contentValue) { char buffer[LOG_VALUE_MAXSIZE]; GetPrivateProfileString(lable, anchor, NULL, buffer, sizeof(buffer), INI_FILE_PATH); contentValue = new char[sizeof(buffer)+1]; strcpy(contentValue, buffer); } ``` 此片段演示了怎样利用 `<windows.h>` 提供的服务去操作本地INI设置文件[^4]。值得注意的是,跨不同OS之间移植这样的解决方案往往需要重新考虑兼容性和替代品的选择。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值