精华内容
下载资源
问答
  • 类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类(父类)和派生类(子类)之间才有意义,并且只能将派生类赋值给基类,包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将...

    类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类(父类)和派生类(子类)之间才有意义,并且只能将派生类赋值给基类,包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用,这在 C++ 中称为向上转型(Upcasting)。相应地,将基类赋值给派生类称为向下转型(Downcasting)。

    将派生类对象赋值给基类对象

    赋值的本质是将数据写入内存中,类的内存只包括成员变量(先不考虑虚函数表指针,成员函数不存在赋值问题),类的赋值其实就是类中成员变量的赋值。在继承部分我们讲了,即使父类的private类型成员,在子类对象中都会被创建并调用父类构造函数进行初始化,只是子类对象不能对其访问。

    用子类对象定义父类对象进行赋值模型,用父类对象给子类对象赋值是不行的
    在这里插入图片描述

    将派生类指针赋值给基类指针(引用和指针类似)

    先说结论:同对象赋值一样只能子给父赋值。用子类指针给父类指针赋值后
    (例如 pa = pb),父类指针(pa)可以访问子类的成员变量,但使用的成员函数依然是父类的成员函数。

    下面说的成员变量和成员函数都是指从父类继承过来那部分

    对象指针的赋值并没有修改对象本身数据,只是改变了指针指向。因此指针改变指向后可以访问子类的成员变量。但是对象的成员函数并不在对象的内存中存储,而是存放在全局数据区(包括全局变量,全局函数,可读写)。而成员函数的第一个参数实际上是this指针(被自动隐藏了),指针赋值后其类型并没有变化所以访问到的还是父类的成员函数。

    向上转型后通过基类的对象、指针、引用只能访问从基类继承过去的成员(包括成员变量和成员函数),不能访问派生类新增的成员。

    将派生类指针赋值给基类指针时到底发生了什么?

    以下面模型为例子:A 派生 B ,D继承B和C
    在这里插入图片描述

    using namespace std;
    class A{
    public:
    	A() :m_a(10), m_a1(11){}
    	void func()
    	{
    		cout << "m-a " << this->m_a << " m-a1 " << this->m_a1 << endl;
    	}
    	int m_a;
    private:
    	int m_a1;
    };
    class B:public A{
    public:
    	B() :m_b(20), m_b1(21){}
    	void func()
    	{
    		cout << "m-a "<<this->m_a<<" m-b " << this->m_b << " m-b1 " << this->m_b1 << endl;
    	}
    	int m_b;
    private:
    	int m_b1;
    };
    class C {
    public:
    	C() :m_c(30), m_c1(31){}
    	void func()
    	{
    		cout  << "m-c " << this->m_c << " m-c1 " << this->m_c1 << endl;
    	}
    	int m_c;
    private:
    	int m_c1;
    };
    class D :public B,public C{
    public:
    	D() :m_d(40), m_d1(41){}
    	void func()
    	{
    		cout << "m-a " << this->m_a << " m-b " << this->m_b <<
    			"m-c " << this->m_c << " m-d " << this->m_d <<" m-d1 "<<this->m_d1<<endl;
    	}
    	int m_d;
    private:
    	int m_d1;
    };
    

    让ABC类指针指向D

    	A*pa = new A;
    	B*pb = new B;
    	C*pc = new C;
    	D*pd = new D;
    	pa = pd;
    	pb = pd;
    	pc = pd;
    

    指针指向同一位置,按理来说其地址都是一样的,我们来输出pa pb pc

    cout << pa << " " << pb << " " << pc << " " << pd << " " << endl;
    结果为:
    0x2495c80 0x2495c80 0x2495c90 0x2495c80 
    
    

    pa pb和pd的地址是一样的,pc的地址一样

    为什么?
    在进行赋值的时候,编译器会为我们进行类型检测和转换,当不能转换的时候编译器会报错,当能转换的时候,会替我们转换。如:

    double pi = 3.14159;
        int n = pi;
        cout<<pi<<", "<<n<<endl;
        运行结果:
    3.14159, 3
    

    同样在进行指针赋值的时候也是如此。将子类指针赋值个父类指针,编译器会做如下处理:让指针指向对象的起始位置
    在这里插入图片描述
    上面是D的内存模型,B类对象和C类对象在内存中的先后顺序是依据继承时的顺序决定的。这就是为什么pa pb和pd的地址相同,pc和pd不同的原因
    如果让D先继承C再继承B那么就是pc和pd地址相同 pa pb和pd不同了。

    展开全文
  • 在C++继承中,很容易遇到一个问题,那就是将派生类指针赋值给基类指针(向上转型)的情况,下面我们就来举例分析: 举一个多继承的例子: #include <iostream> using namespace std; //基类A class A { ...

    在C++继承中,很容易遇到一个问题,那就是将派生类指针赋值给基类指针(向上转型)的情况,下面我们就来举例分析:

    举一个多继承的例子:

    #include <iostream>
    using namespace std;
    
    //基类A
    class A {
    public:
    	A(int a);
    public:
    	void display();
    protected:
    	int m_a;
    };
    A::A(int a) : m_a(a) { }
    void A::display() {
    	cout << "Class A: m_a=" << m_a << endl;
    }
    
    //中间派生类B
    class B : public A {
    public:
    	B(int a, int b);
    public:
    	void display();
    protected:
    	int m_b;
    };
    B::B(int a, int b) : A(a), m_b(b) { }
    void B::display() {
    	cout << "Class B: m_a=" << m_a << ", m_b=" << m_b << endl;
    }
    
    //基类C
    class C {
    public:
    	C(int c);
    public:
    	void display();
    protected:
    	int m_c;
    };
    C::C(int c) : m_c(c) { }
    void C::display() {
    	cout << "Class C: m_c=" << m_c << endl;
    }
    
    //最终派生类D
    class D : public B, public C {
    public:
    	D(int a, int b, int c, int d);
    public:
    	void display();
    private:
    	int m_d;
    };
    D::D(int a, int b, int c, int d) : B(a, b), C(c), m_d(d) { }
    void D::display() {
    	cout << "Class D: m_a=" << m_a << ", m_b=" << m_b << ", m_c=" << m_c << ", m_d=" << m_d << endl;
    }
    
    
    int main() {
    	A *pa = new A(1);
    	B *pb = new B(2, 20);
    	C *pc = new C(3);
    	D *pd = new D(4, 40, 400, 4000);
    
    	cout << "-------更改前-----" << endl;
    	pa->display();
    	pb->display();
    	pc->display();
    	pd->display();
            cout << "-----------------------" << endl;
    
    	cout << "--------更改后-----------" << endl;
        
    	pa = pd;
    	pa->display();
    
    	pb = pd;
    	pb->display();
    
    	pc = pd;
    	pc->display();
    
    	pd->display();
    	cout << "-----------------------" << endl;
    
    	system("pause");
    	return 0;
    }

    运行代码:

            该例中我们定义了多个对象指针,并尝试将派生类指针赋值给基类指针。与对象变量之间的赋值不同的是,对象指针之间的赋值并没有拷贝对象的成员,也没有修改对象本身的数据,仅仅是改变了指针的指向:

            在更改前,每个指针都指向对应类的对象,并且完成了对成员变量的赋值;

            接下来将派生类的指针pd依次赋给pa、pb、pc,由此可以发现:

            当我们将派生类指针 pd 赋值给基类指针 pa后,从运行结果可以看出,调用 display() 函数时虽然使用了派生类的成员变量,但是 display() 函数本身却是基类的。也就是说,将派生类指针赋值给基类指针时,通过基类指针只能使用派生类的成员变量,但不能使用派生类的成员函数,pb、pc也是同样的情况,这是为什么呢?

            a 本来是基类 A 的指针,现在指向了派生类 D 的对象,这使得隐式指针 this 发生了变化,也指向了 D 类的对象,所以最终在 display() 内部使用的是 D 类对象的成员变量,编译器虽然通过指针的指向来访问成员变量,但是却不通过指针的指向来访问成员函数:编译器通过指针的类型来访问成员函数。对于 pa,它的类型是 A,不管它指向哪个对象,使用的都是 A 类的成员函数,只不过该成员函数中使用的是D类对象的成员变量。

            总结一下:编译器通过指针来访问成员变量,指针指向哪个对象就使用哪个对象的数据;编译器通过指针的类型来访问成员函数,指针属于哪个类的类型就使用哪个类的函数。(针对非虚函数!


    补充:

    • 通过基类的对象、指针、引用只能访问从基类继承过去的成员  (包括成员变量和成员函数),不能访问派生类新增的成员。
    • 通过基类的引用或指针,调用基类/派生类的虚函数,要根据运行时根据指针或引用实际指向或引用的类型确定,调用非虚函数时,则无论基类指向的是何种类型,都调用基类的函数 。
    展开全文
  • 常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值。 在C/C++中,....


    常量指针定义:常量是形容词,指针是名词,以指针为中心的一个偏正结构短语。这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针。指针指向的对象是常量,那么这个对象不能被更改。常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值。

    在C/C++中,常量指针是这样声明的:

    1)const int *p;

    2)int const *p;

    例子:

    int a = 5;

    const int b = 8;

    const int *c = &a; // 这是合法的,非法的是对c的使用

    *c = 6; // 非法,但可以这样修改c指向的对象的值:a = 6;

    const int *d = &b; // b是常量,d可以指向b,d被赋值为b的地址是合法的

    我在这里想重点说明的是,在一个函数的定义里,将一个常量指针赋值给变量指针,然后通过这个变量指针是可以修改常量指针指向的对象的。

    但是,编译器会给出一个警告:warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
      p=a;
       ^
    void testp(const int *a,int n)
    {
      int *p;
      p=a;
      p[0]=12;     //修改了数组a[0]的值,而编译器只是给了一个警告,所以,警告也要足够重视。
      a[0]=12;     //直接修改a,编译器会报错,因为定义了const属性。
    }

    转载于:https://www.cnblogs.com/litifeng/p/5831076.html

    展开全文
  • C.152: Never assign a pointer to an array of derived class objects ...C.152:永远不要将派生类数组的指针赋值给基类指针 Reason(原因) Subscripting the resulting base pointer will lead to invalid obj...

    C.152: Never assign a pointer to an array of derived class objects to a pointer to its base

    C.152:永远不要将派生类数组的指针赋值给基类指针

     

    Reason(原因)

    Subscripting the resulting base pointer will lead to invalid object access and probably to memory corruption.

    作为赋值结果的基类指针的下标运算会引起无效的对象访问并可能发生内存破坏。

     

    Example(示例)

    struct B { int x; };
    struct D : B { int y; };
    
    void use(B*);
    
    D a[] = {{1, 2}, {3, 4}, {5, 6}};
    B* p = a;     // bad: a decays to &a[0] which is converted to a B*
    p[1].x = 7;   // overwrite D[0].y
    
    use(a);       // bad: a decays to &a[0] which is converted to a B*

    Enforcement(实施建议)

    • Flag all combinations of array decay and base to derived conversions.

    • 提示所有数组退化和基类类型向派生类类型转换的情况。

    • Pass an array as a span rather than as a pointer, and don't let the array name suffer a derived-to-base conversion before getting into the span

    • 使用span传递数组而不是指针,也不要再放入span之前让数组名经过一次派生类向基类类型的转换。

     

    原文链接:

    https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c151-use-make_shared-to-construct-objects-owned-by-shared_ptrs

     


     

    觉得本文有帮助?欢迎点赞并分享给更多的人。

    阅读更多更新文章,请关注微信公众号【面向对象思考】

    展开全文
  • 给指针赋值或通过指针进行赋值 如果对左操作数进行解引用,则修改的是指针所指对象的值;如果没有使用解引用操作,则修改的是指针本身的值。例如 string s("Hello world"); string* p=&s; cout<<*p&...
  • 今天使用某个函数,其中的参数是类型为char**, 使用了一个固定的二维数组,将其赋值给予,编译时产生警告;在运行的调用的函数(其中没有任何对字符串内容的修改),打印其中的字符串,直接崩溃。 警告内容:...
  • p指向一个数组 b[j][i]=*(*(p+i)+j); *(*(p+i)+j)=b[i][j]; 为什么第一个是error C2100: illegal indirection 第二个是error C2100: illegal indirection和left operand must be l-value ...需要怎么改
  • 在C++继承中,很容易遇到一个问题,那就是将派生类指针赋值给基类指针(向上转型)的情况,下面我们就来举例分析: 举一个多继承的例子: #include <iostream> using namespace std; //基类A class A { ...
  • C.152: Never assign a pointer to an array of derived class objects to a pointer to its baseC.152:永远不要将派生类数组的指针赋值给基类指针Reason(原因)Subscripting the resulting base pointer will lead ...
  • 题目来源于 LeetCode 上第 138 号问题:复制带随机指针的链表。题目难度为 Medium,目前通过率为...题目解析 在原链表的每个节点后面拷贝出一个新的节点依次新的节点的随机指针赋值:cur->next->random = cu...
  • 将字符串指针赋值给数组

    千次阅读 2018-08-08 20:57:57
    比如 char *p=”sdflkjasljfsjlsdfsa”;...将p赋p1 (1)strcpy(p1,p); (2)char *src=”helloworld”; char des[100]={0}; memcpy(des,src,strlen(src)+1); //void *memcpy(void *str1, const...
  • 指针赋值

    千次阅读 2019-09-20 21:46:21
    指针赋值 上学期刚学C语言的时候很迷,老师说要避免野指针,但是空指针似乎又没办法赋值,就只好尽量减少指针的使用。 今天查了一下发现是这样赋值的: 先把要赋值的变量的地址赋空指针,然后才能把变量的值赋...
  • 如题:如上图,但是我们还会经常写这样的代码,例如我的flamingo中有代码如下(已经修正):位于queryresult.cpp中如果fields[i]....备忘一下,以后将char*类型赋值给std::string类型一定记得检测一下是否为空指针。...
  • 1) 如果对左操作数解引用,则修改的是指针所指向的...(即给指针赋值) string s1(“some value”); string *sp1=&s1; string s2(“another”); string *sp2=&s2; *sp1=”a new value” //通过指针赋值,s1变为a
  • 题目来源于 LeetCode 上第 138 号问题:复制带随机指针的链表。题目难度为 Medium,目前...题目解析 在原链表的每个节点后面拷贝出一个新的节点依次新的节点的随机指针赋值:cur->next->random = cur->...
  • 变量名的地址赋值给指针时,必须加取地址符& int*p; int a=1; p=&a;//正确 p=a;//错误 数组名的地址赋值给指针时,给的是首元素地址,和传递参数是一样 int arr[10]; int *p; p=&arr; p=arr; p=&...
  • C++子类的智能指针赋值给父类的智能指针,析构函数不是虚函数,也能正确执行析构 正如大家都知道,如下代码片段: BaseNode *pp1 = new BinaryTreeNode(); // BaseNode 是 BinaryTreeNode的父类 delete pp1; 如果想...
  • class A { }; class B : public A { }; A *p_A=new B; 和A *p_A=NULL; B * p_B=new B; p_A=p_B;两种写法有何区别。 我有一段代码按照下面的方式处理的,结果...(父类指针已经判空了) 为何呢?
  • leetcode117_填充节点下一个右侧节点指针II01—题目给定一个二叉树struct Node {int val;Node *left;Node *right;Node *next;}填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,...
  • void* 指针赋值

    千次阅读 2019-10-17 14:04:17
    void指针可以指向任意类型的数据,亦即可用任意数据类型的指针对void指针赋值。例如: int * pint; void *pvoid; pvoid = pint; /* 不过不能 pint= pvoid; */ 如果要将pvoid赋其他类型指针,则需要强制类型转换如...
  • 字符指针 赋值

    千次阅读 2014-09-17 22:56:47
    字符串赋值给字符指针(char *a=“hello”)的正确理解方式   对于语句 char *a="hello";...但正解是:声明了一个字符指针后,并用字符串常量的第一个字符的地址赋值给指针变量a。  即正确顺序是:1.分配
  • void f(){} class C { public: void g(){} }; int main() { void(*pf)() = f;//没有问题 ...可以直接用f赋值, 而void(C::*pg)() = &C::g; 在等号右边必须要有取地址符号& 谢谢。
  • 字符串指针赋值小结

    千次阅读 2019-12-12 11:57:17
    字符指针赋值探究小结 1, 字符指针有初始值时,不能修改其中字符的值 ...//字符指针赋值给字符指针只能读不能修改字符的值 char *p2 = p1; p1[0] = 'm';//尝试修改,会报错 return 0; } 会报错: 2...
  • 从键盘给指针赋值

    2016-04-20 22:48:25
    如何从键盘给指针赋值? 比如 char *source 是否需要创建空间? 用什么方法能赋值
  • 二维指针赋值

    千次阅读 2013-03-06 18:08:19
    二维指针折腾了很久,最后发现指针不能取得的原因居然是,初始状态没有调整。切记,切记啦,以下是一个简单的代码示例。。 void Get(char **m) { char *jkj=(char*)malloc(sizeof(char)); *m = jkj ; } int ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,398
精华内容 3,359
关键字:

指针赋值给指针