天天看点

c++复习问题

1. 直接打印后置++出错

原因猜测:重载的<<,第二个参数是引用,而不是对象,所以直接打印,匹配不到。

如果修改重载的<<第二个参数是对象,就能打印了。如果重载<<的第二个参数是对象,那么前置++返回引用,也可以打印。

class cla
{
	friend ostream& operator<<(ostream& cout, cla &c1);
public:
	cla(int arg):a(arg){}
	//后置++ a++
	cla operator++(int) {
		cla tmp = *this;
		this->a++;
		return tmp;
	}
	//前置++ ++a
	cla& operator++() {
		this->a++;
		return *this;
	}
private:
	int a;
};
ostream& operator<<(ostream& cout, cla &c1)
{
	cout << c1.a;
	return cout;
}
void test()
{
	cla c1(22), c2(22);
	cla c3 = c1++;
	cla c4 = ++c2;

	cout << c3 << endl;	//22
	cout << c4 << endl;	//23
	//cout << c3++ << endl;	//直接打印后置++出错	
}
           

2. 为什么友元成员函数,必须在friend前先声明在类内才能使用而全局友元函数,友元类,只需要先friend声明,然后可以在后面定义

/*********** 为什么必须得先这样声明,才能使用友元成员函数  **********/
class cla;
class clb:
{
public:
	void show_a(cla &c1);
}
/****************************************************************/
class cla
{
	friend class clb;
	friend class clc;
	friend class cld;
	//friend void clb::show_a(cla &c1);		
public:
	cla(int arg):a(arg){}
private:
	int a;
};
class clb
{
public:
	void show_a(cla &c1) {
		cout << "a = " << c1.a << endl;
	}
};   
           

3. 删除vector中所有的6

调用vector的erase函数后,删除当前迭代器位置元素,迭代器会自动往后走一位。这时候不能再++,不然会漏掉要删的6.应该让迭代器–,之后再++。

题目中,如果找到匹配的要删除元素,定义另外一个迭代器it2 = it。删除时删除这个it2,暂时不明白为什么这样。

int main()
{
    vector<int>v;
    vector<int>::iterator it;
    v.push_back(1);
    v.push_back(6);
    v.push_back(6);
    v.push_back(2);
	for (it = v.begin(); it!= v.end();it++)
	{
		if (*it == 6) {
			v.erase(it);
		}
	}
	for (it = v.begin(); it != v.end(); it++) {
	    cout << *it << endl;
	}
	return 0;
}
1
6
2

//erase后让迭代器--,再++
for (it = v.begin(); it!= v.end();it++)
{
	if (*it == 6) {
		v.erase(it);
		it--;
	}
}
1
2
           

4. 类型转换

(1) 强制类型转换: 都能转,都能用,不安全

不同数据类型之间都可以强制转换,包括:

a: 子类可以强制类型转换为父类

b: 不同类之间可以强制转换

c: 基础数据类型之间可以强制转换

class fa
{
public:
	void print_fa() {   cout << "fa fa" << endl; }
};
class son:public fa
{
public:
    void print_son() {   cout << "son son" << endl; }
};
class other
{
public:
	void print_other() {   cout << "other other" << endl; }
};
int main()
{    	
    fa *pfa = new fa;
    //1. 父类转子类,ok
    son *pson = (son*)pfa;
    pson->print_son();		
 
 	//2.基础数据类型之间转,ok
	int a = 33;
	float f = (float)a;    
	cout << f << endl;

	//3.不同类之间转,ok
	other *poth = (other*)pfa;
	poth->print_other();	

/*
	son son
	33
	other other
*/	    
    return 0;
}
           

(2) static_cast 静态类型转换: 跟强制类型转换差不多,强一点

a: 父类转子类可以

没有发生多态时,父类转子类得到的指针地址不为NULL,所有其实也不安全

b: 基础数据类型之间可以转换

c: 没有继承关系的不同类之间不能转 强一点

int main()
{
    fa *pfa = new fa;
	cout << pfa << endl; 
		
	son *pson = static_cast<son*>(pfa);
	if (pson == NULL)	cout << "pson = NULL" << endl;
	cout << pson << endl;
	pson->print_son();

	son *pson2 = (son*)pfa;
	if (pson2 == NULL)	cout << "pson2 = NULL" << endl;
	cout << pson2 << endl;
	pson2->print_son();
	/*
	00114968
	
	00114968
	son son
	
	00114968
	son son
	*/
	return 0;
}
           

(3) dynamic_cast 动态类型转换: 更严格,更安全

a. 不可以转换基础数据类型,当然没有继承关系,更不可能转了

b. 如果父类没有虚函数,父转子是不可以的,编译过不去.

如果父类有虚函数,可以父转子

c. 没有发生多态时,父类转子类得到的子类指针地址为NULL,可以访问子类元素,但是危险的。但返回值为NULL,不同于静态转换,所以更安全一些。

class fa
{
public:
	void print_fa() {   cout << "fa fa" << endl; }
};
class son:public fa
{
public:
    void print_son() {   cout << "son son" << endl; }
};
int main()
{
    fa *pfa = new fa;
    //son *pson = dynamic_cast<son*>(pfa);   没有发生多态,转不了
	return 0;
}
           

//父类中有虚函数,可以转

class fa
{
public:
	virtual void print_fa() {   cout << "fa fa" << endl; }
};
class son:public fa
{
public:
    void print_son() {   cout << "son son" << endl; }
};

void func(fa *pfa)
{
    son *pson = dynamic_cast<son*>(pfa);
	if (pson == NULL)	pfa->print_fa();
	else pson->print_son();

}
int main()
{
    fa *pfa = new fa;
	cout << pfa << endl; 

	//可以父转子,但没有发生多态时,转换得到的子类指针地址为null,
	//这时候使用子类指针访问是危险的
	son *pson = dynamic_cast<son*>(pfa);
	if (pson == NULL)	cout << "pson = NULL" << endl;
	cout << pson << endl;
	pson->print_son();    

	son *pson2 = (son*)pfa;
	if (pson2 == NULL)	cout << "pson2 = NULL" << endl;
	cout << pson2 << endl;
	pson2->print_son();

	/*
	00584968
	pson = NULL
	00000000
	son son
	00584968
	son son
	bye bye
	*/

	return 0;
}
           

5. 虚继承与虚函数

虚继承,每一次virutal继承,就会多一个虚基类指针。

虚函数发生继承时,子类会继承父类的虚函数表指针,不会再多创建。

class test1
{
	int a;
	virtual void test_func1() {}
	virtual void test_func2() {}
	virtual void test_func3() {}
};
class test1_1:public test1
{
	virtual void test_func4() {}
	virtual void test_func5() {}
};

class test2
{
	int a;
};
class test2_1:virtual public test2
{};
class test2_2:virtual public test2_1
{};
class test2_3: public test2_1
{};
int main() {
	cout << sizeof(test1) << endl;		//8
	cout << sizeof(test1_1) << endl;	//8
	cout << sizeof(test2) << endl;		//4
	cout << sizeof(test2_1) << endl;	//8
	cout << sizeof(test2_2) << endl;	//12
	cout << sizeof(test2_3) << endl;	//8
	return 0;
}
           

6.继承中的类型转换

子类指针强制类型转换或者动态类型转换成父类指针,都会得到父类地址。

子类与父类指针比较,类型不同,进行隐式类型转换,最后结果是相同的。

class A{
    int ma;
};
class B{
    int mb;
};
class C:public A, public B{
    int mc;
};
int main()
{
    C *pc = new C;
    B *pb = dynamic_cast<B*>(pc);
    A *pa = dynamic_cast<A*>(pc);

    cout << pc << endl;
    cout << pb << endl;
    cout << pa << endl;
    cout << (C*)pb << endl;
    if (pc == pb)
        cout << "equal" << endl;
    else 
        cout << "not equal" << endl;

	return 0;
}
0x256f010
0x256f014
0x256f010
0x256f010
equal  
           

7.继承中的同名函数与虚函数

知识点1: 如果调用的函数是普通函数,那么调用的就是这个类中的该函数。

如果调用的函数是虚函数,那么调用的就是最终的子类中的该函数(可能重写了该函数)。

知识点2:

就近调用原则。

如果子类中没有相关函数,调用父辈的,如果父辈中也没有,调用祖父辈的。

例1

class A
{
public:
	void speak() {
		dospeak();		//调用的就是A类中的dospeak
	}
	void dospeak() {
		cout << "aaa" << endl;
	}
};
class B:public A
{
public:
	void dospeak() {
		cout << "bbb" << endl;
	}
};
int main()
{
	B b1;
	b1.speak();			//aaa
	return 0;
}
           

将dospeak改为虚函数

class A
{
public:
	void speak() {
		dospeak();
	}
	virtual void dospeak() {
		cout << "aaa" << endl;
	}
};
int main()
{
	A a1;
	B b1;
	a1.speak();			//aaa
	b1.speak();			//bbb
	return 0;
}
           

例2:

class A
{
protected:
    int m_data;
public:
    A(int data = 0) {
        m_data = data;
    }
    int getdata() {
        return dogetdata();	//dogetdata是虚函数,所以会调用最后子类中的该函数
    }
    virtual int dogetdata() {
        return m_data;
    }
};
class B: public A
{
protected:
    int m_data;
public:
    B(int data = 1) {
        m_data = data;
    }
    int dogetdata() {
        return m_data;
    }
};
class C: public B
{
protected:
    int m_data;
public:
    C(int data = 2) {
        m_data = data;
    }
};

 int main()
 {
    C c(10);
    cout << c.getdata() << endl;	
    cout << c.A::getdata() << endl;
    cout << c.B::getdata() << endl;
    cout << c.C::getdata() << endl;
    cout << c.dogetdata() << endl;
    cout << c.A::dogetdata() << endl;
    cout << c.B::dogetdata() << endl;
    cout << c.C::dogetdata() << endl;
    return 0;
 }
1
1
1
1
1
0
1
1
           

修改1:

class C: public B
{
protected:
    int m_data;
public:
    C(int data = 2) {
        m_data = data;
    }
    int dogetdata() {
        return m_data;
    }
};
 int main()
 {
    C c(10);
    cout << c.getdata() << endl;
    cout << c.A::getdata() << endl;
    cout << c.B::getdata() << endl;
    cout << c.C::getdata() << endl;
    cout << c.dogetdata() << endl;
    cout << c.A::dogetdata() << endl;
    cout << c.B::dogetdata() << endl;
    cout << c.C::dogetdata() << endl;
    return 0;
 }
10
10
10
10
10
0
1
10
           

修改2:

class A
{
protected:
    int m_data;
public:
    A(int data = 0) {
        m_data = data;
    }
    int getdata() {
        return dogetdata();
    }
    int dogetdata() {
        return m_data;
    }
};
class B: public A
{
protected:
    int m_data;
public:
    B(int data = 1) {
        m_data = data;
    }
    int dogetdata() {
        return m_data;
    }
};
class C: public B
{
protected:
    int m_data;
public:
    C(int data = 2) {
        m_data = data;
    }
    int dogetdata() {
        return m_data;
    }
};

 int main()
 {
    C c(10);
    cout << c.getdata() << endl;
    cout << c.A::getdata() << endl;
    cout << c.B::getdata() << endl;
    cout << c.C::getdata() << endl;
    cout << c.dogetdata() << endl;
    cout << c.A::dogetdata() << endl;
    cout << c.B::dogetdata() << endl;
    cout << c.C::dogetdata() << endl;
    return 0;
 }
0
0
0
0
10
0
1
10
           

继续阅读