1. What is the result of running the following C++ code?
#include "stdafx.h"
#include<iostream>
using namespace std;
class A
{
private:
int m_value;
public:
A(int value)
{
m_value = value;
}
void Print1(a)
{
printf("hello world");
}
void Print2(a)
{
printf("%d", m_value);
}
virtual void Print3(a)
{
printf("hello world"); }};int _tmain(int argc, _TCHAR* argv[])
{
A* pA;
pA->Print1();
pA->Print2();
pA->Print3();
return 0;
}
Copy the code
The answer is: Print1 works fine, printing hello World, but when Print2 runs, the program crashes. When Print1 is called, the address of pA is not required, because Print1’s function address is fixed. The compiler passes Print1 a this pointer, which is NULL, but is not used in Print1. As long as the program runs without accessing memory that shouldn’t be accessed, it doesn’t go wrong, so it works fine. When you run print2, you need the this pointer to get the m_value value. Since the this pointer is NULL at this point, the program crashes. For Print3, when C++ calls the virtual function, the address of the function is retrieved from the virtual table pointer in the instance (i.e. the instance to which the this pointer points). Since this step requires accessing the address of the instance (that is, the this pointer), and the this pointer is null, memory access errors occur.
2. What is the result of running the following C++ code?
#include<iostream>
using namespace std;
class A
{
public:
A()
{
Print();
}
virtual void Print(a)
{
cout<<"A is constructed."<<endl; }};class B: public A
{
public:
B()
{
Print();
}
virtual void Print(a)
{
cout<<"B is constructed."<<endl; }};int main(a)
{
A* pA = new B();
delete pA;
return 0;
}
Copy the code
A is constructed. B is constructed. When the constructor of B is called, the constructor of B’s base class A is called first. Then call Print in the constructor of A. Since the part of type B of the instance is not yet constructed, it is essentially an instance of A, and its virtual table pointer points to the virtual table of type A. So Print is called A::Print. We then call the constructor of type B and Print. Print B::Print B::Print B::Print
3. Run the following C++ code. What is the output?
class A{
private:
int n1;
int n2;
public:
A(): n2(0), n1(n2 + 2) {}void Print(a)
{
std: :cout << "n1: " << n1 << ", n2: " << n2 << std: :endl; }};int _tmain(int argc, _TCHAR* argv[])
{
A a;
a.Print();
return 0;
}
Copy the code
The output n1 is a random number and n2 is 0. In C++, member variables are initialized in the same order as they are declared in their type, regardless of the order in which they are initialized in the constructor’s initializer list. So n1 is initialized first, and the parameter n2 that initializes N1 has not been initialized yet and is a random value. When n2 is initialized, it is initialized according to parameter 0, so n2=0.
4. What is the result of compiling and running the following C++ code? (A) Compilation errors; (B) The compilation succeeds and the runtime program crashes; (C) Compilation runs normally, output 10. Please choose the correct answer and analyze the reasons.
class A{
private:
int value;
public:
A(int n)
{
value = n;
}
A(A other)
{
value = other.value;
}
void Print(a)
{
std: :cout << value << std: :endl; }};int _tmain(int argc, _TCHAR* argv[])
{
A a = 10;
A b = a;
b.Print();
return 0;
}
Copy the code
Compilation error. The argument passed in the copy constructor is an instance of A. Because it is passing values, the copy constructor is called to copy the parameter to the actual argument. So if you allow the copy constructor to pass values, you end up with never-ending recursion and stack overflows. Therefore, the C++ standard does not allow copy constructors to pass value arguments, but must pass references or constant references. The argument to the copy constructor needs to be changed to const A& other.
5. Run the following C++ code, what is the output?
class A{
public:
virtual void Fun(int number = 10)
{
std: :cout << "A::Fun with number "<< number; }};class B:public A
{
public:
virtual void Fun(int number = 20)
{
std: :cout << "B::Fun with number "<< number; }};int main(a)
{
B b;
A &a = b;
a.Fun();
return 0;
}
Copy the code
Output B::Fun with number 10. Since a is a reference to an instance of B, B::Fun is called at run time. But the default parameters are determined at compile time. At compile time, the compiler only knows that a is a reference to type A. What type it refers to is not determined at compile time, so the default number is set to 10 as declared by a ::Fun. The key is to understand that determining the value of a default parameter is done at compile time, but determining which type of function is called by a reference or pointer virtual function is done at run time.
6. Run the following C code, what is the output?
char* GetString1(a)
{
char p[] = "Hello World";// refer to the temporary allocated stack of space, when running to the function outside the body, the space will be released
return p;
}
char* GetString2(a)
{
char *p = "Hello World";// points to the global constant area
return p;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("GetString1 returns: %s. \n", GetString1());
printf("GetString2 returns: %s. \n", GetString2());
return 0;
}
Copy the code
Output two lines, the first GetString1 returns: followed by a random string of content, and the second GetString2 Returns: Hello World. The difference between the two functions is that GetString1 is an array and GetString2 is a pointer. When we run GetString1, p is an array, which opens up a chunk of memory and initializes the array by copying “Hello World”. It then returns the first address of the array and exits the function. Since p is a local variable inside GetString1, the array is freed when run outside the function. So when you access the contents of the array in _tmain, the result is random. When we run GetString2, p is a pointer to a constant string in the string constant area. The constant string is global and will not be released by exiting GetString2.
7. What is the output of the C code shown below?
int _tmain(int argc, _TCHAR* argv[])
{
char str1[] = "hello world";/ / 桟 space
char str2[] = "hello world";// stack with space, temporary distribution, address is different
char* str3 = "hello world";/ / constant area
char* str4 = "hello world";// point to the same global constant area
if(str1 == str2)
printf("str1 and str2 are same.\n");
else
printf("str1 and str2 are not same.\n");
if(str3 == str4)
printf("str3 and str4 are same.\n");
else
printf("str3 and str4 are not same.\n");
return 0;
}
Copy the code
This topic is similar to the last one. Str1 and str2 are two string arrays. We allocate two 12-byte Spaces for each of them and copy the contents of “Hello World” into the array. These are two arrays with different initial addresses, so if you compare str1 and str2, you’re going to have different values. Str3 and STR4 are Pointers, and we don’t need to allocate memory for them to store the contents of the string, we just point them to the address of “Hello World” in memory. Since “hello world “is a constant string, it has only one copy in memory, so str3 and STR4 point to the same address. So if you compare str3 to STR4, it’s going to be the same.
8. Run Test. What is the output?
void Test(a)
{
class B
{
public:
B(void)
{
cout<<"B\t";
}
~B(void)
{
cout<<"~B\t"; }};struct C
{
C(void)
{
cout<<"C\t";
}
~C(void)
{
cout<<"~C\t"; }};struct D : B
{
D()
{
cout<<"D\t";
}
~D()
{
cout<<"~D\t";
}
private:
C c;
};
D d;
}
Copy the code
Running result: B C D ~D ~ C ~B When D object is instantiated, the constructor of B is first called because it inherits from B, and then the private member C is initialized. After the parent class is constructed and the private member is initialized, it enters the constructor of D. The objects are then destructed in reverse order. Initialization is different from assignment. Initialization is usually done in the initializer list. Assignment is performed in the constructor body.
9. What is the output of the following program?
class A
{
public:
int a;/ / 4 bytes
char b;/ / 1 byte
double c;//8 bytes, based on this unit of byte alignment, the above two variables are aligned with 8 bytes, plus the current number of bytes, a total of 8+8=16 bytes.
virtual void print(a)The pointer to the virtual function table needs 4 bytes. The pointer to the virtual function table needs 8 bytes
{
cout<<"this is father's function!"<<endl;
}
virtual void print1(a)// The address is stored in the virtual table
{
cout<<"this is father's function1!"<<endl;
}
virtual void print2(a)// No need to allocate memory
{
cout<<"this is father's function2!"<<endl;
}
private:
float d;//4 bytes, which is expanded to 8 bytes
};
class B : A// First load A size: 32 bytes
{
public:
virtual void print(a)// Change the address of the virtual function table
{
cout<<"this is children's function!"<<endl;
}
void print1(a)// Only the function entry address exists, no memory allocation is required
{
cout<<"this is children's function1!"<<endl;
}
private:
char e;//1 byte, byte alignment, expanded to 8 bytes (can be found after inheritance, byte alignment unit also released changes)
};
int main(void)
{
cout<<sizeof(A)<<""<<sizeof(B)<<endl;
system("pause");
return 0;
}
Copy the code
The key to solve this problem is to master the knowledge of byte alignment. See the notes above for details.
10. What happens when the following program is compiled and run?
class A
{
public:
virtual void foo(a) {}};class B
{
public:
virtual void foo(a) {}};class C : public A , public B
{
public:
virtual void foo(a) {}};void bar1(A *pa)
{
B *pc = dynamic_cast<B*>(pa);// Run time traverses the inheritance tree
}
void bar2(A *pa)
{
B *pc = static_cast<B*>(pa);// Two classes are irrelevant, compilation error
}
void bar3(a)
{
C c;
A *pa = &c;
B *pb = static_cast<B*>(static_cast<C*>(pa));// There is inheritance relationship, the compilation is correct
}
Copy the code
For BAR1, dynamic_cast traverses the inheritance tree at run time, so no errors are reported at compile time. However, there is no inheritance relationship between A and B. Static_cast: Displays any type conversion that the compiler implicitly performs. Where for :(1) basic type. We can convert an int to a double(the compiler does an implicit conversion), but we cannot convert an int to a double(there is no such implicit conversion). (2) For user-defined types, if the two classes are unrelated, an error occurs. If there is an inheritance relationship, any transition between the base class and the derived class can be made without error at compile time. So BAR3 can be compiled.
11. What happens if the following procedure is performed?
class A
{
public:
string a;
void f1(a)
{
printf("Hello World");
}
void f2(a)
{
a = "Hello World";
printf("%s",a.c_str());
}
virtual void f3(a)
{
a = "Hello World";
printf("%s",a.c_str());
}
static void f4(a)
{
printf("Hello World"); }};int main(void)
{
A *aptr = NULL; // Create an A object with A null pointer, meaning that the object has only an empty shell and cannot access its member variables with Pointers
aptr->f1(); // The function f1 is called successfully, and only the function entry address is required
aptr->f2(); // Failed to run, call f2 requires access to the member variable
aptr->f3(); // Failed to run, ibid
aptr->f4(); // Static member does not belong to any object
return 0;
}
Copy the code
The solution is shown in the program notes.
12. How does the following function work?
int func(a)
{
char b[2] = {0};
strcpy(b,"aaa");
}
Copy the code
The Debug version crashes, but the Release version works. Debug crashes because it is protected by ASSERT assertions, and Release deletes ASSERT so it works fine. This is not recommended because it overwrites memory that does not belong to you.