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